switch case statement error: case-Ausdrücke müssen konstante Ausdrücke sein

128

Meine Switch-Case-Anweisung funktioniert gestern einwandfrei. Aber als ich den Code heute Morgen früher ausführte, gab mir Eclipse einen Fehler, der die case-Anweisungen in der Farbe Rot unterstrich und sagte: case-Ausdrücke müssen konstante Ausdrücke sein, es ist konstant, ich weiß nicht, was passiert ist. Hier ist mein Code unten:

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

Alle R.id.int sind rot unterstrichen.

HeartlessArchangel
quelle
Können Sie die Definition von R.id.playbtnusw. angeben? Ist alles statisch und endgültig?
Thomas
2
Wahrscheinlich haben Sie Ihr Layout gelöscht / geändert und diese IDs existieren nicht mehr oder so ähnlich ...
Vicente Plata
Die Klasse Rwird normalerweise von den IDE / dev-Tools generiert, daher ist sie normalerweise für die verwendete Android-Version korrekt.
CHao
meine R.id. * sind alle in Ordnung und existieren in der Gen-Klasse von Android .. und es ist auch im Hauptlayout.
HeartlessArchangel

Antworten:

274

In einem regulären Android-Projekt werden Konstanten in der Klasse R der Ressource wie folgt deklariert:

public static final int main=0x7f030004;

Ab ADT 14 werden sie in einem Bibliotheksprojekt jedoch wie folgt deklariert:

public static int main=0x7f030004;

Mit anderen Worten, die Konstanten sind in einem Bibliotheksprojekt nicht endgültig. Daher würde Ihr Code nicht mehr kompiliert.

Die Lösung hierfür ist einfach: Konvertieren Sie die switch-Anweisung in eine if-else-Anweisung.

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

Sie können eine switchAnweisung schnell wie if-elsefolgt in eine Anweisung konvertieren :


Bewegen Sie in Eclipse den Cursor auf das switchSchlüsselwort und drücken Sie Ctrl+ 1und wählen Sie dann

Konvertieren Sie 'switch' in 'if-else'.


Bewegen Sie den Cursor in Android Studio auf das switchSchlüsselwort und drücken Sie Alt+ Enterund wählen Sie dann

Ersetzen Sie 'switch' durch 'if'.

Benito Bertoli
quelle
Ich ändere meine switch-case-Anweisung in else-if-Anweisung. Ich habe mich nur gefragt, ob ich ein neues Android-Projekt erstellt und eine switch-case-Anweisung verwendet habe und gut funktioniert.
HeartlessArchangel
1
Es kann sein, dass Ihr erstes Projekt ein Bibliotheksprojekt verwendet und Ihr neues Projekt nicht.
Benito Bertoli
Ich verstehe nicht, dass es mir leid tut, dass ich hier wirklich ein Anfänger
HeartlessArchangel
7
Zumindest mit Eclipse können Sie den Schalter automatisch in if / else konvertieren. Klicken Sie auf das Schlüsselwort switch. Drücken Sie dann Strg-1
Darren Cato
1
Der Compiler muss den Ausdruck zur Kompilierungszeit kennen. Ohne das finalSchlüsselwort kann eine Variable zur Laufzeit geändert werden.
Benito Bertoli
52

Das Deaktivieren von "Ist Bibliothek" im Projekt Eigenschaften hat für mich funktioniert.

Rick
quelle
2
Klicken Sie mit der rechten Maustaste auf Ihren Projektnamen. Klicken Sie dann auf Eigenschaften -> Android. Unten rechts im Popup befindet sich ein Abschnitt mit der Bezeichnung "Bibliothek". Wenn darunter die Option "Bibliothek ist" aktiviert ist, deaktivieren Sie sie, wenn Ihr Projekt kein Bibliotheksprojekt sein soll. Dann reinigen und wieder aufbauen. Wenn Sie möchten, dass es sich um ein Bibliotheksprojekt handelt, müssen Sie Ihren Schalter in eine if else-Bedingung ändern, wie an anderer Stelle angegeben.
VikingGlen
5
Es gibt Gründe, warum ein Bibliotheksprojekt mit "Ist Bibliothek" gekennzeichnet ist. Dies ist keine richtige Lösung für das Problem - es wird Ihre Android-Projektstruktur beschädigen, indem Bibliotheken erstellt werden, die sich wie normale Apps verhalten sollen.
ADTC
13

Die Lösung kann folgendermaßen erfolgen:

  1. Gerade zuweisen den Wert zu Integer
  2. Machen Variable zu final

Beispiel:

public static final int cameraRequestCode = 999;

Hoffe das wird dir helfen.

Hiren Patel
quelle
8

R.id. *, da ADT 14 nicht mehr als endgültiges statisches int deklariert ist, können Sie es nicht im Switch-Case-Konstrukt verwenden. Sie können stattdessen die if else-Klausel verwenden.

Schwarzer Gürtel
quelle
Ja, ich habe das auf tools.android.com gelesen. Ich habe auch versucht, ein neues Projekt zu erstellen und den obigen Code verwendet. Es funktioniert einwandfrei. Wie ist das?
HeartlessArchangel
1
tools.android.com/recent/buildchangesinrevision14 siehe den Abschnitt "Library Project Revamp"
Blackbelt
6
Warum sie diese Änderung vorgenommen haben, macht keinen Sinn.
Andrew S
8

Eine einfache Lösung für dieses Problem ist:

Klicken Sie auf den Schalter und drücken Sie dann STRG + 1. Dadurch wird der Schalter in die Blockanweisung if-else geändert und das Problem behoben

Pir Fahim Shah
quelle
7

Wie wäre es mit dieser anderen Lösung, um den netten Schalter anstelle eines Wenn-Sonst zu behalten:

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

}

In Ihrem Code können Sie also Folgendes tun:

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

Aufzählungen sind statisch, daher hat dies nur sehr begrenzte Auswirkungen. Das einzige Problem, das Anlass zur Sorge gibt, ist die doppelte Suche (zuerst im internen SparseArray und später in der Switch-Tabelle).

Das heißt, diese Aufzählung kann auch verwendet werden, um die Gegenstände auf fließende Weise abzurufen, wenn dies erforderlich ist, indem ein Verweis auf die ID beibehalten wird ... aber das ist eine Geschichte für eine andere Zeit.

Pablisco
quelle
Enums werden in Android aufgrund ihres aufgeblähten Speichers nicht empfohlen. und das ist der Hauptgrund, warum sie in AOSP nie verwendet werden - und der Grund, warum Sie überall Ints sehen.
ADTC
3

Dieser Fehler wurde ausgelöst, als ich switch in einer Funktion mit in meiner Klasse deklarierten Variablen verwendete:

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

Das Problem wurde gelöst, als ich finalzu Beginn der Klasse die Variablen deklarierte :

final int type_cat=1, type_region=2, type_city=3;
aimiliano
quelle
1
enumist eine bessere Alternative zu intin diesem Fall. Der Aufrufer der Methode kann die Funktion mit ungültigem Typ nicht aufrufen.
nhahtdh
Ich habe bestimmte Int-Typen, also ist es in Ordnung, wenn ich Ints verwende. Allerdings möchte ich ein Beispiel mit Enum wissen: D
Aimiliano
i have specific int types so its ok if i use intsMacht eigentlich keinen Sinn. Beispiel für eine Aufzählung: docs.oracle.com/javase/tutorial/java/javaOO/enum.html
nhahtdh
Ich meine, dass der eingehende int-Variablentyp in der Funktion immer einer dieser 3 Typen sein wird, so dass nichts kaputt geht, danke für das Enum-Beispiel :)
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 anythingDies ist Ihre Annahme. Jemand anderes kann die Funktion mit einer beliebigen Nummer falsch aufrufen. Mit enummüssen Sie nicht davon ausgehen, dass es von der Sprache erzwungen wird.
nhahtdh
2

Ich möchte erwähnen, dass ich auf die gleiche Situation gestoßen bin, als ich versucht habe, meinem Projekt eine Bibliothek hinzuzufügen. Plötzlich zeigten alle switch-Anweisungen Fehler!

Jetzt habe ich versucht, die Bibliothek, die ich hinzugefügt habe, zu entfernen, auch dann hat es nicht funktioniert. Wie auch immer " als ich das Projekt bereinigte ", gingen alle Fehler einfach weg!

Muhammad Riyaz
quelle