Почему AlertDialog.Builder(контекст контекста) принимает активность только как параметр?

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

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

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

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

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

public AlertDialog.Builder(контекст контекст)

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

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

2 ответа

Действие наследует контекст. AlertDialog.Builder задает аргумент Context, потому что он может затем использоваться классом ANY, который является подклассом Context, включая Activity, ListActivity, Service,... (за этим стоит общая идиотская кодировка - вы можете узнать больше об этом читая пункт I8 (по интерфейсам и абстрактным классам) в Joshua Bloch, фантастически эффективная Java).

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

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

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

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

Каждое действие, услуга и т.д. затем вызывает такие вызовы:

myClass(this, ...);

Посмотрите знакомый?

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

Удачи:)


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

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

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

licensed under cc by-sa 3.0 with attribution.