150

My switch-case statement works perfectly fine yesterday. But when I run the code earlier this morning eclipse gave me an error underlining the case statements in color red and says: case expressions must be constant expression, it is constant I don't know what happened. Here's my code below:

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;
        }
    }

All R.id.int are all underlined in red.

4
  • Can you provide the definition of R.id.playbtn etc.? Is everything static and final?
    – Thomas
    Feb 1, 2012 at 8:18
  • 2
    Probably you deleted/modified your layout and those ids don't exist anymore or something like that... Feb 1, 2012 at 8:19
  • The class R is typically generated by the IDE/dev tools, so it's usually correct for the version of Android in use.
    – cHao
    Feb 1, 2012 at 8:20
  • my R.id.* are all fine and exist in the gen class of android.. and its also in the main layout. Feb 1, 2012 at 9:16

10 Answers 10

308

In a regular Android project, constants in the resource R class are declared like this:

public static final int main=0x7f030004;

However, as of ADT 14, in a library project, they will be declared like this:

public static int main=0x7f030004;

In other words, the constants are not final in a library project. Therefore your code would no longer compile.

The solution for this is simple: Convert the switch statement into an if-else statement.

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

You can quickly convert a switch statement to an if-else statement using the following:

In Eclipse
Move your cursor to the switch keyword and press Ctrl + 1 then select

Convert 'switch' to 'if-else'.

In Android Studio
Move your cursor to the switch keyword and press Alt + Enter then select

Replace 'switch' with 'if'.

9
  • 1
    i change my switch-case statement to else-if statement.. It just got me wondering i create a new android project and used a switch-case statement and work fine.. Feb 1, 2012 at 10:13
  • 1
    It could be that your first project is using a library project and your new project isn't. Feb 1, 2012 at 12:32
  • i dont understand that sorry im really a beginner here.. can you explain Feb 1, 2012 at 12:41
  • Your answer was exactly what I needed. I just converted an app project to a library project and was getting a few of these errors, and had not noticed that the final keyword had been dropped from the constant declarations. After reading your answer, saw right away that the old declaration for my constant btnSave was: public static final int btnSave=0x7f0a001f; while the one for the library was: public static int btnSave=0x7f0a001f;
    – Carl
    Jun 25, 2012 at 12:06
  • 3
    The compiler needs the expression to be known at compile time. Without the final keyword, a variable can be changed at runtime. Jun 2, 2015 at 10:10
52

Unchecking "Is Library" in the project Properties worked for me.

2
  • 2
    Right click on your project name. Then click on properties -> Android. On the lower right of the popup is a section labled "Library". Under it, if the "is Library" option is checked, uncheck it if you don't want your project to be a library project. Then clean and rebuild. If you want it to be a library project, then you have to change your switch to an if else conditional as stated elsewhere.
    – VikingGlen
    Nov 4, 2014 at 5:25
  • 6
    There are reasons why a library project is marked with "Is Library". This is not a proper solution to the problem - it will break your Android project structure by making what should be libraries to behave like regular apps.
    – ADTC
    Mar 19, 2015 at 18:33
18

Note for 2023+:

With Android Gradle Plugin 8.0.0 all your R-class resources are by default no longer declared as final/constant (hence won't work in switch statements). If you use the AGP upgrade wizard in Android Studio, it will actually add this line to your gradle.properties to keep the old behavior:

android.nonFinalResIds=false

But if you don't use the wizard or start with a new project, this might come as a surprise. Add above's line manually or use if/else statements instead.

0
13

Solution can be done be this way:

  1. Just assign the value to Integer
  2. Make variable to final

Example:

public static final int cameraRequestCode = 999;

Hope this will help you.

0
11

Simple solution for this problem is :

Click on the switch and then press CTL+1, It will change your switch to if-else block statement, and will resolve your problem

9

R.id.*, since ADT 14 are not more declared as final static int so you can not use in switch case construct. You could use if else clause instead.

3
7

How about this other solution to keep the nice switch instead of an 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);
    }

}

So in your code you can do this:

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;
    }
}

Enums are static so this will have very limited impact. The only window for concern would be the double lookup involved (first on the internal SparseArray and later on the switch table)

That said, this enum can also be utilised to fetch the items in a fluent manner, if needed by keeping a reference to the id... but that's a story for some other time.

2
  • Enums are discouraged in Android due to their memory bloat; and that is the major reason why they are never used in AOSP - and the reason why you see ints everywhere.
    – ADTC
    Mar 19, 2015 at 18:32
  • 1
3

It was throwing me this error when I using switch in a function with variables declared in my class:

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;
    }
}

The problem was solved when I declared final to the variables in the start of the class:

final int type_cat=1, type_region=2, type_city=3;
6
  • 1
    enum is a better alternative to int in this case. The caller of the method won't be able to call the function with invalid type.
    – nhahtdh
    Sep 10, 2013 at 15:22
  • i have specific int types so its ok if i use ints. However i would like to know an example with enum :D
    – aimiliano
    Sep 11, 2013 at 11:02
  • i have specific int types so its ok if i use ints Doesn't really make sense. Regarding enum example: docs.oracle.com/javase/tutorial/java/javaOO/enum.html
    – nhahtdh
    Sep 11, 2013 at 21:41
  • 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 thanks for the enum example :)
    – aimiliano
    Sep 12, 2013 at 8:19
  • 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 This is your assumption. Someone else can call the function incorrectly with arbitrary number. With enum, you don't need to assume, it is enforced by the language.
    – nhahtdh
    Sep 12, 2013 at 9:14
2

I would like to mention that, I came across the same situation when I tried adding a library into my project. All of a sudden all switch statements started to show errors!

Now I tried to remove the library which I added, even then it did not work. how ever "when I cleaned the project" all the errors just went off !

0

Simply declare your variable to final

Not the answer you're looking for? Browse other questions tagged or ask your own question.