android - example - Lanzamiento de diálogo "No se puede agregar la ventana: el token null no es para una aplicación" con getApplication() como contexto
input dialog android (24)
Mi actividad está intentando crear un AlertDialog que requiere un contexto como parámetro. Esto funciona como se espera si uso:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Sin embargo, desconfío de usar "esto" como contexto debido a la posibilidad de fugas de memoria cuando la Actividad se destruye y se recrea incluso durante algo simple como una rotación de pantalla. De una publicación relacionada en el blog del desarrollador de Android :
Hay dos formas fáciles de evitar las fugas de memoria relacionadas con el contexto. La más obvia es evitar escapar del contexto fuera de su propio alcance. El ejemplo anterior mostró el caso de una referencia estática, pero las clases internas y su referencia implícita a la clase externa pueden ser igualmente peligrosas. La segunda solución es utilizar el contexto de la aplicación. Este contexto vivirá mientras su aplicación esté activa y no dependa del ciclo de vida de las actividades. Si planea mantener objetos de larga duración que necesitan un contexto, recuerde el objeto de la aplicación. Puede obtenerlo fácilmente llamando a Context.getApplicationContext () o Activity.getApplication ().
Pero para AlertDialog()
ni getApplicationContext()
ni getApplication()
son aceptables como Contexto, ya que arroja la excepción:
"No se puede agregar la ventana: el token null no es para una aplicación"
Por referencias: 1 , 2 , 3 , etc.
Entonces, ¿debería esto realmente considerarse un "error", ya que se nos recomienda oficialmente que utilicemos Activity.getApplication()
y, sin embargo, no funcione como se anuncia?
Jim
No puede mostrar una
window/dialog
aplicación a través de un contexto que no sea una actividad o servicio . Intenta pasar una referencia de actividad válida
***** versión kotlin *****
Debe pasar this@YourActivity
lugar de applicationContext
o baseContext
Creo que también puede suceder si está intentando mostrar un diálogo desde un hilo que no es el hilo principal de la interfaz de usuario.
Use runOnUiThread()
en ese caso.
Después de echar un vistazo a la API, puede pasar el cuadro de diálogo a su actividad o obtener actividad si está en un fragmento, luego limpie a la fuerza con dialog.dismiss () en los métodos de retorno para evitar fugas.
Aunque no se indica explícitamente en ningún lugar que conozca, parece que se le devuelve el diálogo en los OnClickHandlers solo para hacer esto.
En la Activity
haga clic en el botón mostrando un cuadro de diálogo
Dialog dialog = new Dialog(MyActivity.this);
Trabajó para mi.
En lugar de getApplicationContext()
, simplemente use ActivityName.this
.
En mi caso trabajo:
this.getContext();
Estaba usando ProgressDialog
en un fragmento y recibía este error al pasar getActivity().getApplicationContext()
como el parámetro constructor. getActivity().getBaseContext()
a getActivity().getBaseContext()
tampoco funcionó.
La solución que funcionó para mí fue pasar getActivity()
; es decir
progressDialog = new ProgressDialog(getActivity());
Ha identificado correctamente el problema cuando dijo "... para AlertDialog () ni getApplicationContext () ni getApplication () son aceptables como Contexto, ya que arroja la excepción: ''No se puede agregar la ventana - el token null no es para Una aplicación''"
Para crear un diálogo, necesita un contexto de actividad o un contexto de servicio , no un contexto de aplicación (tanto getApplicationContext () como getApplication () devuelven un contexto de aplicación).
Así es como se obtiene el contexto de actividad :
(1) En una actividad o un servicio:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
(2) En un fragmento: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Las pérdidas de memoria no son un problema que sea intrínseco a la referencia "this", que es la referencia de un objeto a sí mismo (es decir, la referencia a la memoria asignada real para almacenar los datos del objeto). Le sucede a cualquier memoria asignada para la cual el recolector de basura (GC) no puede liberarse después de que la memoria asignada haya superado su vida útil útil.
La mayoría de las veces, cuando una variable queda fuera del alcance, la memoria será reclamada por el GC. Sin embargo, las fugas de memoria pueden ocurrir cuando la referencia a un objeto en poder de una variable, por ejemplo, "x", persiste incluso después de que el objeto haya sobrevivido a su vida útil útil. Por lo tanto, la memoria asignada se perderá mientras "x" contenga una referencia a ella porque GC no liberará la memoria mientras esa memoria aún esté siendo referenciada. A veces, las pérdidas de memoria no son evidentes debido a una cadena de referencias a la memoria asignada. En tal caso, el GC no liberará la memoria hasta que se hayan eliminado todas las referencias a esa memoria.
Para evitar pérdidas de memoria, revise su código para detectar errores lógicos que hagan que la memoria asignada sea referenciada indefinidamente por "esto" (u otras referencias). Recuerde comprobar también las referencias de la cadena. Aquí hay algunas herramientas que puede usar para ayudarlo a analizar el uso de la memoria y encontrar esas molestas pérdidas de memoria:
Intente getParent()
en el lugar de argumento del contexto como el nuevo AlertDialog.Builder(getParent());
Espero que funcione, funcionó para mí.
Otra posibilidad es crear un diálogo como el siguiente:
final Dialog dialog = new Dialog(new ContextThemeWrapper(
this, R.style.MyThemeDialog));
Para futuros lectores, esto debería ayudar:
public void show() {
if(mContext instanceof Activity) {
Activity activity = (Activity) mContext;
if (!activity.isFinishing() && !activity.isDestroyed()) {
dialog.show();
}
}
}
Pequeño truco: puedes evitar que la actividad se destruya con GC (Por supuesto, no debes hacerlo, pero puede ayudar en algunas situaciones):
public class PostActivity extends Activity {
...
private Context contextForDialog = null;
...
public void onCreate(Bundle savedInstanceState) {
...
contextForDialog = this;
}
...
private void showAnimatedDialog() {
mSpinner = new Dialog(contextForDialog);
mSpinner.setContentView(new MySpinner(contextForDialog));
mSpinner.show();
}
...
}
Puede continuar usando getApplicationContext()
, pero antes de usar, debe agregar este indicador: dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
, y el error no se mostrará.
Agregue el siguiente permiso a su manifiesto:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Si está fuera de la Actividad, entonces necesita usar en su función "NameOfMyActivity.this" como actividad de Actividad, ejemplo:
public static void showDialog(Activity activity) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage("Your Message")
.setPositiveButton("Yes", dialogClickListener)
.setNegativeButton("No", dialogClickListener).show();
}
//Outside your Activity
showDialog(NameOfMyActivity.this);
Si está utilizando un fragmento y está utilizando el mensaje AlertDialog / Toast, use getActivity () en el parámetro de contexto.
Me gusta esto
ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();
Si está utilizando un fragmento y está utilizando un mensaje AlertDialog / Toast
, use getActivity()
en el parámetro de contexto.
Trabajó para mi.
¡Aclamaciones!
Su diálogo no debe ser un "objeto de larga duración que necesita un contexto". La documentación es confusa. Básicamente si haces algo como:
static Dialog sDialog;
(note la estática )
Luego en una actividad en algún lugar que hiciste
sDialog = new Dialog(this);
Es probable que pierda la actividad original durante una rotación o similar que destruya la actividad. (A menos que limpie en onDestroy, pero en ese caso probablemente no haga que el objeto Dialog sea estático)
Para algunas estructuras de datos, tendría sentido hacerlas estáticas y basadas en el contexto de la aplicación, pero generalmente no para cosas relacionadas con la interfaz de usuario, como los diálogos. Así que algo como esto:
Dialog mDialog;
...
mDialog = new Dialog(this);
Está bien y no debería filtrar la actividad, ya que mDialog se liberaría con la actividad ya que no es estática.
Trate de usar el contexto de una actividad que estará debajo del diálogo. Pero tenga cuidado cuando use la palabra clave "this", ya que no funcionará siempre.
Por ejemplo, si tiene TabActivity como host con dos pestañas, y cada pestaña es otra actividad, y si intenta crear un diálogo desde una de las pestañas (actividades) y si usa "esto", obtendrá una excepción. El diálogo de caso debe estar conectado a la actividad del host que alberga todo y es visible. (Se puede decir contexto de actividad de los padres más visible)
No encontré esta información de ningún documento, sino por intentarlo. Esta es mi solución sin una base sólida. Si alguien con un mejor conocimiento, puede comentar.
Tuve que enviar mi contexto a través de un constructor en un adaptador personalizado mostrado en un fragmento y tuve este problema con getApplicationContext (). Lo resolví con:
this.getActivity().getWindow().getContext()
en la devolución de llamada onCreate
los fragmentos.
Usar this
no funcionó para mí, pero MyActivityName.this
hizo. Espero que esto ayude a cualquiera que no pueda hacer que this
funcione.
Use MyDialog md = new MyDialog(MyActivity.this.getParent());
añadiendo
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
y
"android.permission.SYSTEM_ALERT_WINDOW"/>
en el manifiesto
Funciona para mi ahora. Incluso después de cerrar y abrir la aplicación, me dio el error en ese momento.
en Actividad solo usa:
MyActivity.this
en Fragmento:
getActivity();