139

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.

Jav_Rock
  • 22,059
  • 20
  • 123
  • 164
HeartlessArchangel
  • 1,737
  • 4
  • 13
  • 17

10 Answers10

299

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'.

Benito Bertoli
  • 25,285
  • 12
  • 54
  • 61
  • 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.. – HeartlessArchangel Feb 01 '12 at 10:13
  • 1
    It could be that your first project is using a library project and your new project isn't. – Benito Bertoli Feb 01 '12 at 12:32
  • i dont understand that sorry im really a beginner here.. can you explain – HeartlessArchangel Feb 01 '12 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 '12 at 12:06
  • So, why `switch` specifically doesn't allow that? – Muhammed Refaat Jun 02 '15 at 09:46
  • 2
    The compiler needs the expression to be known at compile time. Without the `final` keyword, a variable can be changed at runtime. – Benito Bertoli Jun 02 '15 at 10:10
  • Note that `final` is not sufficient. If the value of the `final` variable is created through a method, it will sadly not work either. – Arglanir May 18 '18 at 07:27
  • Special thanks for the shortcuts to auto convert switch/case to if/else! – FrankKrumnow Jun 28 '18 at 11:04
  • Note that as of Android Gradle Plugin 8.0.0, ALL project R.class resources are non-final by default – Till - Appviewer.io Jul 27 '23 at 17:08
52

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

rick
  • 529
  • 4
  • 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 04 '14 at 05:25
  • 5
    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 '15 at 18:33
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.

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
10

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

Pir Fahim Shah
  • 10,505
  • 1
  • 82
  • 81
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.

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
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.

pablisco
  • 14,027
  • 4
  • 48
  • 70
  • 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 '15 at 18:32
  • 1
    http://stackoverflow.com/questions/5143256/why-was-avoid-enums-where-you-only-need-ints-removed-from-androids-performanc – pablisco Apr 16 '15 at 09:28
4

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.

Till - Appviewer.io
  • 4,529
  • 1
  • 31
  • 35
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;
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
aimiliano
  • 1,105
  • 2
  • 12
  • 18
  • 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 '13 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 '13 at 11:02
  • `i have specific int types so its ok if i use ints` Doesn't really make sense. Regarding enum example: http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html – nhahtdh Sep 11 '13 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 '13 at 08: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 '13 at 09:14
  • hmm ok your argument is true if someone else doesn't know how to call the function or pass wrong int input but someone could put in the default branch return false if he changes the return of the function also to Boolean. anyway i suppose its a better way to call a function with enum variables preset by the user. – aimiliano Sep 12 '13 at 09:50
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 !

Muhammad Riyaz
  • 2,832
  • 2
  • 26
  • 30
0

Simply declare your variable to final

Manoj Rawat
  • 260
  • 4
  • 6