Android: ProgressDialog.show () se bloquea con getApplicationContext


109

Parece que no puedo entender por qué está sucediendo esto. Este código:

mProgressDialog = ProgressDialog.show(this, "", getString(R.string.loading), true);

funciona bien. Sin embargo, este código:

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

lanza la siguiente excepción:

W/WindowManager(  569): Attempted to add window with non-application token WindowToken{438bee58 token=null}.  Aborting.
D/AndroidRuntime( 2049): Shutting down VM
W/dalvikvm( 2049): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
E/AndroidRuntime( 2049): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 2049): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tastekid.TasteKid/com.tastekid.TasteKid.YouTube}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.access$2100(ActivityThread.java:116)
E/AndroidRuntime( 2049):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
E/AndroidRuntime( 2049):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 2049):    at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.main(ActivityThread.java:4203)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
E/AndroidRuntime( 2049):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 2049): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.view.ViewRoot.setView(ViewRoot.java:460)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
E/AndroidRuntime( 2049):    at android.app.Dialog.show(Dialog.java:238)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:107)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:90)
E/AndroidRuntime( 2049):    at com.tastekid.TasteKid.YouTube.onCreate(YouTube.java:45)
E/AndroidRuntime( 2049):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
E/AndroidRuntime( 2049):    ... 11 more

¿Alguna idea de por qué está sucediendo esto? Llamo a esto desde el onCreatemétodo.


Si está utilizando Fragment, stackoverflow.com/questions/24825114/…
Yeo

Respuestas:


42

¿Qué versión de API estás usando? Si tengo razón sobre cuál es el problema, esto se solucionó en Android 1.6 (API versión 4).

Parece que la referencia del objeto que getApplicationContext()devuelve solo apunta a nulo. Creo que está teniendo un problema similar al que tuve yo en el sentido de que parte del código en el onCreate()se está ejecutando antes de que la ventana termine de construirse. Esto va a ser un truco, pero intente lanzar un nuevo hilo en unos cientos de milisegundos (IIRC: 300-400 parecía funcionar para mí, pero tendrá que jugar) que abre su ProgressDialog e inicia cualquier otra cosa que necesite ( p. ej. red IO). Algo como esto:

@Override
public void onCreate(Bundle savedInstanceState) {
    // do all your other stuff here

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            mProgressDialog = ProgressDialog.show(
               YouTube.this.getApplicationContext(), "",
               YouTube.this.getString(R.string.loading), true);

            // start time consuming background process here
        }
    }, 1000); // starting it in 1 second
}

6
Estoy usando 1.6. Estoy bastante seguro de que cualquier operación de la interfaz de usuario debe realizarse en el hilo de la interfaz de usuario, por lo que llamar a ProgressDialog.show () en un hilo separado podría fácilmente ser un gran problema. Todavía creo que esto es extraño.
Felix

3
En el ejemplo que le di, no está realizando operaciones de la interfaz de usuario en otro hilo, el otro hilo simplemente está llamando al hilo de la interfaz de usuario diciéndole que abra el diálogo.
Jeremy Logan

Definitivamente es extraño y es un truco total, pero funcionó para mí. Necesito probar el error que estaba teniendo en 1.6 para ver si puedo DEJAR de usar esto.
Jeremy Logan

1
No es 'extraño' ni es un 'truco total', ¡es un enfoque perfectamente legítimo!
KomodoDave

1
@KomodoDave Me acabo de dar cuenta de que tengo el mismo problema. Sin embargo, el truco malo está en el temporizador. Esta es una ventana de tiempo que espera fallar de forma intermitente en algunas situaciones. La clave del éxito puede estar en configurar un temporizador más corto, verificar si la aplicación está lista, volver a reproducir la acción hasta que lo esté. Probablemente también limite cuántas veces intentar.
Jim Rush

129

Estoy usando la versión 2.1 de Android con nivel de API 7. Me enfrenté a este (o similar) problema y lo resolví usando esto:

Dialog dialog = new Dialog(this);

en lugar de esto:

Dialog dialog = new Dialog(getApplicationContext());

Espero que esto ayude :)


4
Tuve un problema similar, pero estaba usando un ActivityGroup. La única forma en que pude resolver este error fue usando getParent () en su lugar.
brack

20
¿Cómo responde esto a su pregunta? Pregunta POR QUÉ el segundo no funciona, mientras que el primero sí.
Burkhard

3
-1, 'esto' es lo mismo que 'getApplicationContext ()' para algunos de nosotros.
Kellogs

Sigue siendo un consejo útil en desarrollo para 2.1
Carlos P

64

Para mi trabajo cambiando

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

a

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

Lo extraño es que el primero se puede encontrar en el tutorial de Google y la gente obtiene un error al respecto ...


1
única solución que funciona para mí con una alerta dentro de un evento onclick
Tobias

Esta es la forma correcta de hacerlo. Nunca use ApplicationContext a menos que sea estrictamente necesario y, sobre todo, nunca lo use para mostrar elementos de la IU. Para eso son las actividades (y, en última instancia, los fragmentos).
Martin Marconcini

Éste es el indicado. thissolo no funcionará si lo hace dentro de, por ejemplo, un oyente de clic.
Ayman Salah

23

No creo que esto sea un problema de tiempo en torno a un contexto de aplicación nulo

Intente extender la aplicación dentro de su aplicación (o simplemente úsela si ya lo ha hecho)

public class MyApp extends Application

Haga que la instancia esté disponible como singleton privado. Esto nunca es nulo

private static MyApp appInstance;

Cree un ayudante estático en MyApp (que usará el singleton)

    public static void showProgressDialog( CharSequence title, CharSequence message )
{
    prog = ProgressDialog.show(appInstance, title, message, true); // Never Do This!
}

¡¡AUGE!!

Además, consulte la respuesta del ingeniero de Android aquí: WindowManager $ BadTokenException

Una de las causas de este error puede ser intentar mostrar una ventana / diálogo de la aplicación a través de un contexto que no es una actividad.

Ahora, estoy de acuerdo, no tiene sentido que el método tome un parámetro Context, en lugar de Activity.


10

Después de leer las respuestas anteriores, descubrí que, para mi situación, lo siguiente solucionó el problema.

Esto arrojó el error

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(getApplicationContext());
        dialog.show();              
    }
});

Basado en las respuestas anteriores que sugirieron que el contexto era el incorrecto, cambié getApplicationContext () para recuperar el contexto de la Vista pasada a los botones del método onClick.

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(v.getContext());
        dialog.show();              
    }
});

No entiendo completamente el funcionamiento de Java, por lo que podría estar equivocado, pero supongo que para mi situación específica, la causa podría haber estado relacionada con el hecho de que el fragmento anterior se definió en una clase de Actividad abstracta; heredado y utilizado por muchas actividades, ¿quizás eso contribuyó al hecho de que getApplicationContext () no devuelve un contexto válido? (Solo una suposición).


Las soluciones mejor puntuadas probablemente funcionan para la mayoría de los casos, pero su técnica v.getContext () parece resolver los casos más difíciles como el mío. Mi conocimiento empírico de Java me lleva a pensar que un contexto proveniente de un método onCreated no es exactamente lo mismo que un contexto proveniente de la Vista de un método onClick. ¡Vota arriba!
Josh

¡Esto me salvó el día!
Alejandro Luengo

6

Estoy creando una vista de mapa con superposiciones detalladas. Estaba creando mi itemizedoverlay así desde mi mapActivity:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

Descubrí que obtendría la excepción "android.view.WindowManager $ BadTokenException: No se puede agregar la ventana - el token nulo no es para una aplicación" cuando se activaba el método onTap de mi itemizedoverlay (cuando se toca la ubicación en la vista del mapa).

Descubrí que si simplemente pasaba 'this' en lugar de 'getApplicationContext ()' a mi constructor, el problema desaparecía. Esto parece apoyar la conclusión de alienjazzcat. extraño.


1
Gracias, este es exactamente mi problema.
Kon

4

Para las actividades que se muestran dentro de TabActivities, use getParent ()

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

en vez de

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

3

Para Android 2.2
Use este código:

//activity is an instance of a class which extends android.app.Activity
Dialog dialog = new Dialog(activity);

en lugar de este código:

// this code produces an ERROR:
//android.view.WindowManager$BadTokenException: 
//Unable to add window -- token null is not for an application
Context mContext = activity.getApplicationContext();
Dialog dialog = new Dialog(mContext);

Observación: Mi cuadro de diálogo personalizado se crea fuera del activity.onCreateDialog(int dialogId)método.


3

Tratar -

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

Necesario cuando la actividad actual está dentro de un grupo de actividades
htafoya

2

Tenía un problema similar con (compatibilidad) fragmentos en los que el uso de un getActivity()plazo deProgressDialog.show() choques de TI. Estoy de acuerdo en que se debe a la sincronización.

Una posible solución:

mContext = getApplicationContext();

if (mContext != null) {
    mProgressDialog = ProgressDialog.show(mContext, "", getString(R.string.loading), true);
}

En lugar de usar

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

Coloque mContext lo antes posible para darle más tiempo para captar el contexto. Todavía no hay garantía de que esto funcione, solo reduce la probabilidad de un accidente. Si aún no funciona, tendrá que recurrir al truco del temporizador (que puede causar otros problemas de sincronización, como cerrar el cuadro de diálogo más tarde).

Por supuesto, si puedes usar thiso ActivityName.this, es más estable porque thisya apunta a algo. Pero en algunos casos, como ocurre con ciertas arquitecturas Fragment, no es una opción.


2

(Para futuras referencias)

Creo que es porque hay diferencias en el contexto de la aplicación y el contexto de la actividad, como se explica aquí: http://www.doubleencore.com/2013/06/context/

Lo que significa que no podemos mostrar el diálogo usando el contexto de la aplicación. Eso es.


2

Para usar diálogos dentro de actividades, hágalo de esta manera:

private Context mContext;
private AlertDialog.Builder mBuilder;

@Override
protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     mContext = this;

     //using mContext here refering to activity context
     mBuilder = new AlertDialog.Builder(mContext);
     //...
     //rest of the code
     //...
}

Para usar diálogos dentro de fragmentos, hágalo de esta manera:

private Context mContext;
private AlertDialog.Builder mBuilder;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View mRootView = inflater.inflate(R.layout.fragment_layout, container, false);
      mContext = getActivity();

      //using mContext here refering to fragment's hosting activity context
      mBuilder = new AlertDialog.Builder(mContext);
      //...
      //rest of the code
      //...
      return mRootView;
}

Eso es ^ _ ^


1

Lo que hice para evitar esto fue crear una clase base para todas mis actividades donde almaceno datos globales. En la primera actividad, guardé el contexto en una variable en mi clase base así:

Clase base

public static Context myucontext; 

Primera actividad derivada de la clase base

mycontext = this

Luego uso mycontext en lugar de getApplicationContext al crear diálogos.

AlertDialog alertDialog = new AlertDialog.Builder(mycontext).create();

Es una pena que esta solución no obtenga más votos a favor. De todas las posibles soluciones presentadas aquí, esta es la única que funcionó para mí en una AsyncTask
ckn

1

Si está llamando a ProgressDialog.show () en un fragmento, enviar el mContext a Activity funcionó para mí.

     ProgressDialog pd = new ProgressDialog((Activity) mContext);

1

Este es un problema común. Use en thislugar de getApplicationContext() Eso debería resolver su problema


0

Implementé Alert Dialog para lanzar excepciones a la vista de actividad actual.

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

Dada la misma excepción de ventana. Escribo código para alerta de onCreate (). Tan simple que usé context = this;después de la setContentView()declaración enonCreate() método. Tomé la variable de contexto como global comoContext context;

La muestra de código es

static Context context;

 public void onCreate(Bundle savedInstanceState)  { 
        super.onCreate(savedInstanceState); 


        setContentView(R.layout.network); 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        context = this;
.......

La muestra del método de alerta es

private void alertException(String execMsg){
        Log.i(TAG,"in alertException()..."+context);
        Log.e(TAG,"Exception :"+execMsg);
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
.......

Funciona bien para mí. De hecho, busqué este error en StackOverflow y encontré esta consulta. Después de leer todas las respuestas de esta publicación, lo intenté de esta manera para que funcione. Pensé que esta es una solución simple para superar la excepción.

Gracias, Rajendar


0

Si tiene un problema en groupActivity, no use esto. PARENT es una estática del Parent ActivityGroup.

final AlertDialog.Builder builder = new AlertDialog.Builder(GroupActivityParent.PARENT);

en vez de

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.