2011-03-25 12 views
27

En mi proceso de aprendizaje continuo (cuadros de diálogo esta vez), he descubierto que esto funciona:¿Por qué AlertDialog.Builder (Context context) solo acepta Activity como parámetro?

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

Mientras que el siguiente no funciona (falla en tiempo de ejecución con WindowManager $ BadTokenException):

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

no entiendo por qué, porque the constructor para AlertDialog.Builder está definido para aceptar Contexto como parámetro, no Actividad:

AlertDi pública alog.Builder (Contexto contexto)

Constructor usando un contexto para este constructor y el AlertDialog que crea.

¿Qué me falta?

+2

también es cierto para otros cuadros de diálogo. Buena pregunta, +1 – bigstones

+0

@bigstones Descubrí otro hilo que trata de un problema similar, pero no hay explicación: http://stackoverflow.com/questions/3968170/android-prompt-users-input-using-a-dialog – an00b

+0

Mi suposición es que el Constructor no solo solicita una Actividad porque evitaría que las futuras API tengan otros tipos de contextos que puedan mostrar un diálogo. – bigstones

Respuesta

17

Una actividad hereda un contexto. AlertDialog.Builder especifica un argumento de contexto porque puede ser utilizado por CUALQUIER clase que sea una subclase de contexto, incluyendo una actividad, actividad de lista, servicio, ... (Hay una expresión de codificación común detrás de esto: puede obtener más información al respecto leyendo el Ítem I8 (en Interfaces y clases abstractas) en la fantástica Java Eficaz de Joshua Bloch).

getApplicationContext() devuelve el contexto para su aplicación, que es básicamente el mismo que el contexto de sus actividades, y "en su mayoría" es lo que lo está desanimando. Los detalles no están claros, pero este es un problema ampliamente encontrado, y la respuesta típica es usar el contexto que escribirá la alerta en la pantalla. Tenga en cuenta que eso es no el que devuelve getApplicationContext().

Ahora, si eres como yo, puedes decir "pero estoy trabajando en una clase que no hereda de Activity, por eso quiero usar getApplicationContext() para esto en primer lugar - ¡duh!" En realidad, no hablo tan groseramente como eso; p ... el punto es que he estado aquí también. Lo arreglé así: 1) pregúntese: "¿Tengo mi código de UI AlertDialog en una clase que no es de actividad porque quiero compartirlo entre actividades ... o incluso en ListActivities, Servicios, ...?". Si no, hmmm ... ¿realmente tiene llamadas de la IU de AlertDialog en un código que no puede garantizar que tendrá acceso a la IU (y por lo tanto al contexto)? Si es así, reconsidere su diseño.

Suponiendo que desea compartir esta clase en Actividades, ... la respuesta queda clara. Usted quiere que su clase sea utilizable por una variedad de personas que llaman, probablemente cada uno con su propio contexto: por lo que la persona que llama tiene que pasar su contexto en su clase como un argumento:

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

Cada actividad, servicio, etc. a continuación, hace llamadas de este modo:

myClass(this, ...);

familiar?

¡Ten cuidado! si compartes código, debes considerar la posibilidad de que diferentes llamadas entren en tu código compartido en paralelo, con todas las ramificaciones. Eso está más allá de nuestro alcance aquí ...

Diviértete :)

+0

Gracias por su respuesta. Desafortunadamente, todavía no entiendo por qué AlertDialog.Builder (contexto contextual) solo acepta la actividad como parámetro. ¿Estás diciendo que el contexto de esto no es lo mismo que this.getApplicationContext()? Por favor explique. – an00b

+0

sí, parece que el contexto de la actividad es un superconjunto del contexto de la aplicación: la actividad especializa el contexto de la aplicación agregando elementos como los utilizados por AlertDialog. Para su información, esta es mi comprensión basada en la lectura de los hallazgos de otros sobre este mismo tema. Lo que más me da confianza es el fis: pasar una actividad a mi código trabajado. – DJC

+13

La respuesta "clara" sigue siendo problemático, debido a que dos actividades no necesariamente sólo se pueden desear compartir la misma "clase", es posible que quieran compartir el mismo "ejemplo" de esa clase. Si ese es el caso, entonces no puede permitir que ambas actividades creen la clase compartida con su propio contexto. Esta es realmente una opción de diseño horrible de Android. ¿Por qué demonios querrías crear AlertDialogs, y no tenerlos emergente sobre todas las Actividades? iOS te permite lanzar UIAlertViews desde cualquier lugar. Android debería, también. – Nate

6

AlertDialog es una subclase de Dialog, que se ha asociado un Window, que tiene una LayoutParams asociado. Uno de esos parámetros es el type de la ventana. El tipo predeterminado es TYPE_APPLICATION_ATTACHED_DIALOG, que requiere una ventana principal.

El WindowManager asociado a una actividad está configurado para usar la ventana de la actividad como la ventana principal. El WindowManager asociado con una Aplicación no tiene una ventana primaria asociada.

En pocas palabras: para mostrar correctamente un cuadro de diálogo, debe cambiar el tipo de ventana predeterminado a un tipo que no requiere una ventana primaria, o debe usar un contexto que tenga una ventana principal asociada.

Cuestiones relacionadas