In OnClickListener kann ich nicht auf viele Dinge zugreifen - wie gehe ich vor?

79

Innerhalb eines OnClickListener kann ich nicht auf die meisten Variablen "außerhalb" des Bereichs zugreifen, wie folgt:

findViewById(R.id.Button01).setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent mainApps = new Intent(Intent.ACTION_MAIN);
                mainApps.addCategory(Intent.CATEGORY_LAUNCHER);
                List<ActivityInfo> activities = this.getPackageManager().queryIntentActivities(mainApps, 0);
                /*
                Intent intent = new Intent("com.sygic.drive/com.sygic/drive/.SygicDriveActivity");
                startActivity(intent);*/
            }

        });

In diesem Beispiel muss der PacketManager abgerufen werden, und ich kann ihn nicht abrufen, da der Kontext im OnClickListener nicht verfügbar ist.

Ich könnte außen eine statische Referenz erstellen und innen verwenden, aber ist das richtig? Scheint seltsam, das die ganze Zeit tun zu müssen?

Ted
quelle

Antworten:

229

Ersetzen Sie thisin Ihrem Code durch MyActivity.thisMyActivity den Klassennamen Ihrer Activity-Unterklasse.

Erläuterung: Sie erstellen eine anonyme innere Klasse, wenn Sie diesen Teil Ihres Codes verwenden:
new OnClickListener() {
Anonyme innere Klassen haben einen Verweis auf die Instanz der Klasse, in der sie erstellt wurden. Es sieht so aus, als würden Sie sie in einer Activity-Unterklasse erstellen, da findViewById eine ist Aktivitätsmethode. Aktivitäten sind ein Kontext. Sie müssen also nur den Verweis darauf verwenden, den Sie automatisch haben.

Lance Nanek
quelle
1
Ich habe eine Weile gegoogelt, nur um "MyActivity.this" zu finden. Es scheint jetzt so einfach. Danke für die Information!
TCCV
Was ist mit dem Zugriff auf Variablen, die den Fehler verursachen Cannot refer to a non-final variable table inside an inner class defined in a different method? Ich kann nicht über auf diese zugreifen MyActivity.this.
Michael
Das sind lokale Variablen. Wenn sie sich nicht ändern, können Sie ihre Erklärung so ändern, dass sie endgültig ist. Wenn sie sich ändern, aber bevor Ihre innere Klasse definiert ist, können Sie einfach vorher eine endgültige Version definieren. Beispiel: final int myFinalErrorCode = errorCode. Andernfalls müssen Sie ein Mitglied für die Aktivität, auf die Sie zugreifen, oder für die innere Klasse erstellen und festlegen.
Lance Nanek
Ich verstehe das nicht, aber es funktioniert wie du gesagt hast Activity.this.doStg(). Kannst du hier @LanceNanek eine URL mit detaillierterer Erklärung anfordern? Hat es etwas mit reaktiver Programmierung zu tun?
Murt
Sehen Sie das Beispiel "ShadowTest.this" hier: docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Lance Nanek
10

Sie können auch die OnClickListener-Schnittstelle in Ihrer Klasse implementieren und die Notwendigkeit einer anonymen inneren Klasse vermeiden. Dann würden Sie den On-Click-Listener folgendermaßen einstellen:

findViewById(R.id.Button01).setOnClickListener(this);

Wenn Sie mehrere Schaltflächen mit einem Listener haben, können Sie eine switch-Anweisung mit view.getId () (die der ID der Ansicht in R.id entspricht) verwenden, um zwischen ihnen zu unterscheiden.

Al.
quelle
4

Sie können einige Dinge tun: Sie können eine innere Klasse erstellen, die den onClickListener implementiert, und die erforderlichen Argumente an den Konstruktor der Klasse übergeben. Ich finde das immer noch nicht den saubersten Ansatz. Normalerweise erstelle ich einfach eine andere Methode, um meine Aktion auszuführen. In onClick (View v) würde ich so etwas tun.

onClick(View v){doMyAction(myParams)}

private void doMyAction(Object params){//do stuff}

Und übergeben Sie einfach die erforderlichen Parameter von der Listener-Methode an die Methode außerhalb des Listeners.

broschb
quelle
Ok, komisch, dass du das so machen musst, aber ich denke, es funktioniert. =)
Ted
0

Ändern Sie den verwendeten Intent-Konstruktor in Intent (Kontext, Klassenname) und verwenden Sie getApplicationContext () in Ihrer inneren Klasse. Mein Problem trotzdem gelöst.

WayneSplatter
quelle