Почему AlertDialog.Builder (Context context) принимает Activity только в качестве параметра? - PullRequest
34 голосов
/ 25 марта 2011

В процессе обучения (в этот раз диалоговые окна) я обнаружил, что это работает:

  AlertDialog.Builder builder = new AlertDialog.Builder(this);

Хотя следующее не работает (происходит сбой во время выполнения с WindowManager $ BadTokenException):

  AlertDialog.Builder builder = new AlertDialog.Builder(this.getApplicationContext());

Я не понимаю почему, потому что конструктор для AlertDialog.Builder определен для принятия Context в качестве параметра, а не Activity:

public AlertDialog.Builder (Context context)

Конструктор, использующий контекст для этого построителя и AlertDialog, который он создает.

Что мне не хватает?

Ответы [ 2 ]

25 голосов
/ 29 марта 2011

Деятельность наследует контекст. AlertDialog.Builder указывает аргумент Context, потому что он может использоваться ЛЮБЫМ классом, который является подклассом Context, включая Activity, ListActivity, Service, ... (За этим стоит распространенная идиома кодирования - вы можете узнать больше об этом читая Item I8 (об интерфейсах и абстрактных классах) в фантастической «Эффективной Java» Джошуа Блоха).

getApplicationContext () возвращает контекст для вашего приложения, который в основном совпадает с контекстом вашей деятельности, и «главным образом» - это то, что вас отталкивает. Детали неясны, но это широко распространенная проблема, и типичным ответом является использование контекста, который будет выводить предупреждение на экран. Обратите внимание, что это , а не тот, который возвращен getApplicationContext ().

Теперь, если вы похожи на меня, вы можете сказать «но я работаю в классе, который не наследуется от Activity - вот почему я хочу использовать getApplicationContext () для этого в первую очередь - дух!» Вообще-то я не так грубо говорю, суть в том, что я тоже был здесь. Я исправил это так: 1) спросите себя «у меня есть код AlertDialog пользовательского интерфейса в неактивном классе, потому что я хочу поделиться им между действиями .. или даже между ListActivities, Services, ...?». Если нет, хм ... у вас действительно есть вызовы пользовательского интерфейса AlertDialog в коде, который вы не можете гарантировать, будет ли иметь доступ к пользовательскому интерфейсу (и, следовательно, контексту)? Если это так, пересмотрите свой дизайн.

Предполагая, что вы хотите поделиться этим классом в Деятельности, ... ответ становится ясным. Вы хотите, чтобы ваш класс мог использоваться различными вызывающими, каждый из которых, вероятно, имел свой собственный контекст: поэтому вызывающий должен передать свой контекст в ваш класс в качестве аргумента:

myClass(Context theContext, ...) { ... }

Затем каждое действие, услуга и т. Д. Совершает такие звонки:

myClass(this, ...);

Выглядит знакомо?

Будьте осторожны! что, если вы делитесь кодом, вы должны учитывать возможность параллельного ввода различных вызовов в ваш общий код со всеми многочисленными последствиями. Это за пределами нашей области здесь ...

Веселитесь :) 1023 *

13 голосов
/ 24 сентября 2016

AlertDialog является подклассом Dialog , с которым связано Окно , с которым связан LayoutParams . Одним из таких параметров является тип окна . Тип по умолчанию - TYPE_APPLICATION_ATTACHED_DIALOG , для которого требуется родительское окно.

WindowManager , связанный с действием, настроен на использование окна действия в качестве родительского окна. WindowManager, связанный с приложением, не имеет связанного родительского окна.

Итог: чтобы успешно отобразить диалоговое окно, вы должны либо изменить тип окна по умолчанию на тип, для которого не требуется родительское окно, либо вы должны использовать контекст, связанный с родительским окном.

...