¿Por qué AlertDialog.Builder (Context context) solo acepta Activity como parámetro?

En mi proceso de aprendizaje continuo (cuadros de diálogo esta vez), descubrí que esto funciona:

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

Si bien lo siguiente no funciona (falla en el tiempo de ejecución con WindowManager $ BadTokenException):

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

No entiendo por qué, porque el constructor de AlertDialog.Builder está definido para aceptar el contexto como un parámetro, no como actividad:

public AlertDialog.Builder (Contexto contextual)

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

¿Qué me estoy perdiendo?

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 encoding 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 más o menos el mismo que el contexto de sus actividades, y lo “más” 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 ese no es el devuelto por getApplicationContext ().

Ahora, si eres como yo, puedes decir “pero estoy trabajando en una clase que no hereda de Activity, por lo que 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. Desea que su clase sea utilizable por una variedad de personas que llaman, cada una probablemente con su propio contexto: por lo que la persona que llama debe pasar su contexto a su clase como argumento:

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

Cada actividad, servicio, etc. luego realiza llamadas como estas:

myClass(this, ...);

¿Parecer 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 scope aquí …

Que te diviertas 🙂

AlertDialog es una subclase de Diálogo , que tiene una Ventana asociada, que tiene un LayoutParams asociado. Uno de esos parámetros es el tipo de ventana. El tipo predeterminado es TYPE_APPLICATION_ATTACHED_DIALOG , que requiere una ventana principal.

El WindowManager asociado con 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 con éxito 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 padre asociada.

Intereting Posts