2011-03-25 1 views
27

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

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

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

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

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

общественного AlertDi alog.Builder (Context контекст)

Constructor используя контекст для этого строителя и AlertDialog это создает.

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

+2

Это также верно для других диалогов. Хороший вопрос, +1 – bigstones

+0

@bigstones Я открыл еще один поток, посвященный аналогичной проблеме, но не объяснил: http://stackoverflow.com/questions/3968170/android-prompt-users-input-using-a-dialog – an00b

+0

Мое предположение что Builder не просто запрашивает действие, потому что это предотвратит появление в будущем API других контекстов, которые могут отображать диалог. – bigstones

ответ

17

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

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

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

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

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

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

myClass(this, ...);

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

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

Удачи :)

+0

Спасибо за ваш ответ. К сожалению, я до сих пор не понимаю, почему AlertDialog.Builder (контекст контекста) принимает значение Activity только как параметр. Вы говорите, что этот контекст - это не то же самое, что this.getApplicationContext()? Пожалуйста, объясни. – an00b

+0

Да, кажется, что контекст Activity является надмножеством контекста приложения - Activity специализирует контекст приложения, добавляя такие вещи, как те, которые используются AlertDialog. FYI, это мое понимание, основанное на чтении других результатов по этому же вопросу. Вещь, в которой я больше всего уверен, - это fis: передача активности в мой код. – DJC

+13

«Ясный» ответ по-прежнему проблематичен, потому что две операции могут не только разделять один и тот же «класс», они могут захотеть использовать один и тот же «экземпляр» этого класса. Если это так, то вы не можете позволить обеим действиям создавать общий класс со своим контекстом. Это действительно ужасный выбор для Android. Почему бы вам никогда не захотеть создать AlertDialogs, и не иметь их всплывающие окна над всеми действиями? iOS позволяет запускать UIAlertViews из любого места. Android тоже. – Nate

6

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

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

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

Смежные вопросы