Wewnątrz OnClickListener nie mam dostępu do wielu rzeczy - jak podejść?

79

Wewnątrz OnClickListener nie mogę uzyskać dostępu do większości zmiennych „poza” zakresem, na przykład:

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

        });

w tym przykładzie muszę pobrać PacketManager i nie mogę go pobrać, ponieważ nie mam dostępnego kontekstu wewnątrz OnClickListener.

Mógłbym stworzyć statyczne odniesienie na zewnątrz i użyć go w środku, ale czy to prawda? Wydaje się dziwne, że trzeba to robić przez cały czas?

Przetrząsać
źródło

Odpowiedzi:

231

Zastąp thisw kodzie MyActivity.thisgdzie MyActivity to nazwa klasy Twojej podklasy Activity.

Objaśnienie: Tworzysz anonimową klasę wewnętrzną, używając tej części swojego kodu:
new OnClickListener() {
Anonimowe klasy wewnętrzne mają odniesienie do instancji klasy, w której zostały utworzone. Wygląda na to, że tworzysz ją wewnątrz podklasy Activity, ponieważ findViewById jest Metoda działania. Działania są kontekstem, więc wszystko, co musisz zrobić, to użyć odniesienia do niego, które masz automatycznie.

Lance Nanek
źródło
1
Od jakiegoś czasu szukam w Google, aby znaleźć „MyActivity.this”. Teraz wydaje się to takie proste. Dzięki za informację!
TCCV,
A co z dostępem do zmiennych, które powodują błąd Cannot refer to a non-final variable table inside an inner class defined in a different method? Nie mogę uzyskać do nich dostępu przez MyActivity.this.
Michael,
To są zmienne lokalne. Jeśli się nie zmienią, możesz zmienić ich deklarację, aby miała w sobie ostateczną. Jeśli się zmieniają, ale zanim zdefiniowana zostanie twoja klasa wewnętrzna, możesz po prostu zdefiniować ostateczną wersję tuż przed. Np .: final int myFinalErrorCode = errorCode. W przeciwnym razie musisz zrobić coś takiego, jak utworzyć i ustawić element członkowski w działaniu, do którego masz dostęp lub w klasie wewnętrznej.
Lance Nanek
Nie rozumiem tego zachowania, ale działa tak, jak powiedziałeś Activity.this.doStg(). Czy możesz załączyć tutaj @LanceNanek jakiś adres URL z bardziej szczegółowym wyjaśnieniem. Czy jest to w jakiś sposób związane z programowaniem reaktywnym?
murt
Zobacz przykład „ShadowTest.this” tutaj: docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Lance Nanek
10

Możesz również zaimplementować interfejs OnClickListener w swojej klasie i uniknąć potrzeby anonimowej klasy wewnętrznej. Następnie należy ustawić odbiornik po kliknięciu w następujący sposób:

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

Jeśli masz wiele przycisków korzystających z jednego nasłuchiwania, możesz użyć instrukcji switch z view.getId () (co odpowiada identyfikatorowi widoku w R.id), aby je rozróżnić.

Glin.
źródło
4

Jest kilka rzeczy, które możesz zrobić, możesz stworzyć wewnętrzną klasę, która implementuje onClickListener i przekazać niezbędne argumenty do konstruktora klasy. Nadal nie uważam tego za najczystsze podejście. Zwykle po prostu tworzę inną metodę wykonania mojej akcji. Więc w onClick (View v) zrobiłbym coś takiego.

onClick(View v){doMyAction(myParams)}

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

I po prostu przekaż potrzebne parametry z metody detektora do metody poza detektorem.

broschb
źródło
Ok, dziwne, że musisz to zrobić, ale myślę, że to działa. =)
Ted
0

Zmień używany konstruktor Intent na Intent (kontekst, nazwa klasy) i użyj metody getApplicationContext () w Twojej innerclass. I tak rozwiązałem mój problem.

WayneSplatter
źródło