Внутри OnClickListener я не могу получить доступ ко многим вещам - как подойти?

79

Внутри OnClickListener я не могу получить доступ к большинству переменных «вне» области, например:

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

        });

в этом примере мне нужно получить PacketManager, но я не могу его получить, так как у меня нет контекста, доступного внутри OnClickListener.

Я мог бы сделать статическую ссылку снаружи и использовать ее внутри, но правильно ли это? Кажется странным делать это все время?

Тед
источник

Ответы:

231

Замените thisв своем коде, MyActivity.thisгде MyActivity - это имя класса вашего подкласса Activity.

Объяснение: вы создаете анонимный внутренний класс, когда используете эту часть вашего кода:
new OnClickListener() {
анонимные внутренние классы имеют ссылку на экземпляр класса, в котором они созданы. Похоже, вы создаете его внутри подкласса Activity, потому что findViewById является Метод деятельности. Действие - это контекст, поэтому все, что вам нужно сделать, это использовать ссылку на него, которая у вас есть автоматически.

Лэнс Нанек
источник
1
Некоторое время я искал в Google, чтобы найти "MyActivity.this". Теперь это кажется таким простым. Спасибо за информацию!
TCCV
Как насчет доступа к переменным, которые дают ошибку Cannot refer to a non-final variable table inside an inner class defined in a different method? Я не могу получить к ним доступ через MyActivity.this.
Майкл
Это локальные переменные. Если они не меняются, вы можете изменить их декларацию так, чтобы она была окончательной. Если они меняются, но до того, как ваш внутренний класс будет определен, вы можете просто определить окончательную версию прямо перед этим. Например: final int myFinalErrorCode = errorCode. В противном случае вам нужно сделать что-то вроде make и установить член в действии, к которому вы обращаетесь, или во внутреннем классе.
Лэнс Нанек,
Я не понимаю этого поведения, но он работает, как вы сказали Activity.this.doStg(). Не могли бы вы прикрепить сюда @LanceNanek какой-нибудь URL с более подробным объяснением, пожалуйста. Это как-то связано с реактивным программированием?
murt
См. Пример «ShadowTest.this» здесь: docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Лэнс Нанек,
10

Вы также можете реализовать интерфейс OnClickListener в своем классе и избежать необходимости в анонимном внутреннем классе. Затем вы должны установить прослушиватель щелчка следующим образом:

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

Если у вас есть несколько кнопок, использующих один слушатель, вы можете использовать оператор switch с view.getId () (который соответствует идентификатору представления в R.id), чтобы различать их.

Al.
источник
4

Вы можете сделать несколько вещей. Вы можете создать внутренний класс, который реализует onClickListener и передать необходимые аргументы в конструктор класса. Я все еще не считаю этот подход самым чистым. Обычно я просто создаю другой метод для выполнения своего действия. Итак, в onClick (View v) я бы сделал что-то вроде этого.

onClick(View v){doMyAction(myParams)}

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

И просто передайте необходимые параметры из метода слушателя в метод вне слушателя.

Broschb
источник
Ладно, странно, что ты должен так поступать, но я думаю, это работает. =)
Ted
0

Измените используемый конструктор Intent на Intent (context, classname) и используйте getApplicationContext () в своем внутреннем классе. Все равно решил мою проблему.

WayneSplatter
источник