切换case语句错误:case表达式必须为常量表达式


128

我的转换案例声明昨天运行良好。但是,当我今天早些时候运行代码时,eclipse给了我一个错误,强调了红色的case语句,并说:case表达式必须是常量表达式,它是常量,我不知道发生了什么。这是我的代码如下:

public void onClick(View src)
    {
        switch(src.getId()) {
        case R.id.playbtn:
            checkwificonnection();
            break;

        case R.id.stopbtn:
            Log.d(TAG, "onClick: stopping srvice");
            Playbutton.setImageResource(R.drawable.playbtn1);
            Playbutton.setVisibility(0); //visible
            Stopbutton.setVisibility(4); //invisible
            stopService(new Intent(RakistaRadio.this,myservice.class));
            clearstatusbar();
            timer.cancel();
            Title.setText(" ");
            Artist.setText(" ");
            break;

        case R.id.btnmenu:
            openOptionsMenu();
            break;
        }
    }

所有R.id.int都用红色下划线。


您可以提供R.id.playbtnetc 的定义吗?一切都是静态的和最终的吗?
托马斯(Thomas)

2
可能是您删除/修改了布局,而这些ID不再存在或类似的东西……
Vicente Plata

该类R通常由IDE / dev工具生成,因此对于所使用的Android版本通常是正确的。
cHao 2012年

我的R.id. *都很好,并且存在于android ..的gen类中,并且也存在于主布局中。
HeartlessArchangel 2012年

Answers:


274

在常规的Android项目中,资源R类中的常量声明如下:

public static final int main=0x7f030004;

但是,从ADT 14开始,在图书馆项目中,它们将这样声明:

public static int main=0x7f030004;

换句话说,常数在库项目中不是最终的。因此,您的代码将不再编译。

解决方案很简单:将switch语句转换为if-else语句。

public void onClick(View src)
{
    int id = src.getId();
    if (id == R.id.playbtn){
        checkwificonnection();
    } else if (id == R.id.stopbtn){
        Log.d(TAG, "onClick: stopping srvice");
        Playbutton.setImageResource(R.drawable.playbtn1);
        Playbutton.setVisibility(0); //visible
        Stopbutton.setVisibility(4); //invisible
        stopService(new Intent(RakistaRadio.this,myservice.class));
        clearstatusbar();
        timer.cancel();
        Title.setText(" ");
        Artist.setText(" ");
    } else if (id == R.id.btnmenu){
        openOptionsMenu();
    }
}

http://tools.android.com/tips/non-constant-fields

您可以使用以下命令快速将switch语句转换为语句if-else

在Eclipse中,
将光标移动到switch关键字,然后按Ctrl+,1然后选择

将'switch'转换为'if-else'。

在Android Studio
中将光标移至switch关键字,然后按Alt+,Enter然后选择

将“ switch”替换为“ if”。


我将我的switch-case语句更改为else-if语句。.这让我想知道我创建一个新的android项目并使用switch-case语句并正常工作
。–

1
可能是您的第一个项目正在使用库项目,而新项目却没有。
贝尼托·贝托利

我不明白,对不起,我真的是一个初学者。.您能解释一下吗
HeartlessArchangel 2012年

7
至少eclipse可以让您自动将切换转换为if / else。单击switch关键字。然后按ctrl-1
Darren Cato

1
编译器需要在编译时就知道表达式。如果没有final关键字,则可以在运行时更改变量。
贝尼托·贝托利

52

在项目属性中取消选中“是库”对我有用。


2
右键单击您的项目名称。然后单击属性-> Android。在弹出窗口的右下角是一个标有“库”的部分。在其下,如果选中了“是库”选项,则如果您不希望您的项目成为库项目,请取消选中它。然后清理并重建。如果您希望它成为一个库项目,则必须将其切换到其他地方所述的if if else条件。
VikingGlen 2014年

5
将图书馆项目标记为“是图书馆”是有原因的。这不是解决此问题的适当方法-通过使应具有类似常规应用程序行为的库,将破坏您的Android项目结构。
ADTC 2015年


8

R.id. *,因为ADT 14并未更多地声明为最终的static int,所以您不能在转换案例中使用它。您可以改用if else子句。


是的,我已经在tools.android.com上阅读了该文章,我也尝试创建一个新项目并使用了上面的代码,它的工作原理很好。
HeartlessArchangel 2012年

1
tools.android.com/recent/buildchangesinrevision14看到“图书馆计划改造”一节
黑带

6
他们为什么做出这种改变是没有道理的。
安德鲁·S


7

如何保持美观的开关而不是if-else的其他解决方案呢:

private enum LayoutElement {
    NONE(-1),
    PLAY_BUTTON(R.id.playbtn),
    STOP_BUTTON(R.id.stopbtn),
    MENU_BUTTON(R.id.btnmenu);

    private static class _ {
        static SparseArray<LayoutElement> elements = new SparseArray<LayoutElement>();
    }

    LayoutElement(int id) {
        _.elements.put(id, this);
    }

    public static LayoutElement from(View view) {
        return _.elements.get(view.getId(), NONE);
    }

}

因此,您可以在代码中执行以下操作:

public void onClick(View src) {
    switch(LayoutElement.from(src)) {
    case PLAY_BUTTTON:
        checkwificonnection();
        break;

    case STOP_BUTTON:
        Log.d(TAG, "onClick: stopping srvice");
        Playbutton.setImageResource(R.drawable.playbtn1);
        Playbutton.setVisibility(0); //visible
        Stopbutton.setVisibility(4); //invisible
        stopService(new Intent(RakistaRadio.this,myservice.class));
        clearstatusbar();
        timer.cancel();
        Title.setText(" ");
        Artist.setText(" ");
        break;

    case MENU_BUTTON:
        openOptionsMenu();
        break;
    }
}

枚举是静态的,因此影响将非常有限。唯一需要关注的窗口是涉及的双重查找(首先在内部SparseArray上,然后在switch表上)

就是说,如果需要,还可以通过保留对id的引用,以一种流畅的方式来获取该枚举……但这是另一些故事了。


由于Android的内存过大,因此不鼓励枚举。这就是为什么它们从未在AOSP中使用的主要原因-也是随处可见整数的原因。
ADTC 2015年


3

当我在类中声明了变量的函数中使用switch时,将引发此错误:

private void ShowCalendar(final Activity context, Point p, int type) 
{
    switch (type) {
        case type_cat:
            break;

        case type_region:
            break;

        case type_city:
            break;

        default:
            //sth
            break;
    }
}

当我final在类的开头声明变量时,该问题已解决:

final int type_cat=1, type_region=2, type_city=3;

1
enumint在这种情况下是更好的选择。该方法的调用者将无法使用无效类型调用该函数。
nhahtdh 2013年

我有特定的int类型,所以如果我使用int也可以。但是我想知道一个枚举的例子:D
aimiliano

i have specific int types so its ok if i use ints真的没有道理。关于枚举示例:docs.oracle.com/javase/tutorial/java/javaOO/enum.html
nhahtdh 2013年

我的意思是,函数中传入的int变量类型将始终是这3种类型之一,因此对于枚举示例,它不会破坏任何内容:)
aimiliano

i mean that the incoming int variable type in the function will always be one of these 3 types so it won't break anything这是您的假设。其他人可能会错误地使用任意数字调用该函数。使用enum,您无需假设,它是由语言强制执行的。
nhahtdh

2

我想提及的是,当我尝试在项目中添加库时遇到了同样的情况。突然所有switch语句开始显示错误!

现在,我试图删除我添加的库,即使它不起作用。但是“ 当我清理项目时 ”所有错误都消失了!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.