ошибка оператора switch case: выражения case должны быть постоянными выражениями

129

Вчера мой оператор switch-case отлично работал. Но когда я запустил код ранее этим утром, затмение дало мне ошибку, подчеркнув операторы 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 подчеркнуты красным.

HeartlessArchangel
источник
Можете ли вы дать определение R.id.playbtnи т. Д.? Все ли статично и окончательно?
Томас
2
Вероятно, вы удалили / изменили свой макет, и эти идентификаторы больше не существуют или что-то в этом роде ...
Висенте Плата
Класс Rобычно создается с помощью инструментов IDE / dev, поэтому он обычно подходит для используемой версии Android.
cHao 01
мои R.id. * все в порядке и существуют в классе gen для android .. а также в основном макете.
HeartlessArchangel

Ответы:

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-case на оператор else-if .. Это просто заставило меня задуматься, я создаю новый проект для Android, использую оператор switch-case и работаю нормально ..
HeartlessArchangel
1
Возможно, ваш первый проект использует проект библиотеки, а ваш новый - нет.
Бенито Бертоли
я не понимаю, что извините, я действительно новичок здесь .. вы можете объяснить
HeartlessArchangel
7
По крайней мере, eclipse позволит вам автоматически преобразовать переключатель в if / else. щелкните по ключевому слову переключателя. затем нажмите ctrl-1
Даррен Кейто
1
Компилятору необходимо, чтобы выражение было известно во время компиляции. Без finalключевого слова переменную можно изменить во время выполнения.
Бенито Бертоли
52

У меня сработало снятие флажка «Библиотека» в свойствах проекта.

стог
источник
2
Щелкните правой кнопкой мыши имя вашего проекта. Затем нажмите «Свойства» -> «Android». В правом нижнем углу всплывающего окна находится раздел «Библиотека». Если под ним установлен флажок «Библиотека», снимите его, если вы не хотите, чтобы ваш проект был проектом библиотеки. Затем очистите и восстановите. Если вы хотите, чтобы это был проект библиотеки, вы должны изменить свой переключатель на условное if else, как указано в другом месте.
VikingGlen
5
Есть причины, по которым проект библиотеки помечен как «Библиотека». Это неправильное решение проблемы - это нарушит структуру вашего проекта Android, заставив то, что должно быть библиотеками, вести себя как обычные приложения.
ADTC
13

Решение можно сделать так:

  1. Просто назначить на значение в Integer
  2. Сделать переменную в финале

Пример:

public static final int cameraRequestCode = 999;

Надеюсь, что это поможет вам.

Хирен Патель
источник
8

R.id. *, поскольку ADT 14 больше не объявляется как final static int, поэтому вы не можете использовать его в конструкции switch case. Вместо этого вы можете использовать предложение if else.

Черный пояс
источник
да, я читал это на tools.android.com, я также пытался создать новый проект и использовал приведенный выше код, и он отлично работает .. как это?
HeartlessArchangel
1
tools.android.com/recent/buildchangesinrevision14 см. раздел «Обновление проекта библиотеки»
Blackbelt
6
Почему они сделали это изменение, не имеет смысла.
Эндрю С.
8

Простое решение этой проблемы:

Щелкните переключатель, а затем нажмите CTL + 1, он изменит ваш переключатель на оператор блока if-else и решит вашу проблему.

Пир Фахим Шах
источник
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, а затем в таблице переключателей)

Тем не менее, это перечисление также можно использовать для быстрой выборки элементов, если необходимо, сохраняя ссылку на идентификатор ... но это история для другого раза.

pablisco
источник
Перечисления не приветствуются в Android из-за чрезмерного увеличения памяти; и это основная причина, почему они никогда не используются в AOSP, и причина, по которой вы видите целые числа везде.
ADTC
3

Это вызывало у меня эту ошибку, когда я использовал переключатель в функции с переменными, объявленными в моем классе:

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;
aimiliano
источник
1
enumявляется лучшей альтернативой intв этом случае. Вызывающий метод не сможет вызвать функцию с недопустимым типом.
nhahtdh
У меня есть определенные типы int, поэтому все в порядке, если я использую int. Однако я хотел бы знать пример с enum: D
aimiliano
i have specific int types so its ok if i use intsНа самом деле это не имеет смысла. Что касается примера перечисления: docs.oracle.com/javase/tutorial/java/javaOO/enum.html
nhahtdh
Я имею в виду, что тип входящей переменной int в функции всегда будет одним из этих трех типов, поэтому он ничего не сломает, спасибо за пример с перечислением :)
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 начали показывать ошибки!

Теперь я попытался удалить добавленную мной библиотеку, но даже тогда это не сработало. как бы то ни было " когда я чистил проект " все ошибки просто уходили!

Мухаммад Рияз
источник