web-dev-qa-db-fra.com

Android: ProgressDialog.show () se bloque avec getApplicationContext

Je n'arrive pas à comprendre pourquoi cela se produit. Ce code:

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

fonctionne très bien. Cependant, ce code:

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

lève l'exception suivante:

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

Des idées pourquoi cela se produit? J'appelle cela depuis la méthode onCreate.

107
Felix

Quelle version de l'API utilisez-vous? Si je ne me trompe pas, le problème a été résolu dans Android 1.6 (API version 4).

Il semble que la référence d'objet que getApplicationContext() renvoie ne renvoie que des points nuls. Je pense que vous rencontrez un problème similaire à celui que j’avais: une partie du code de la onCreate() est en cours d’exécution avant la construction de la fenêtre. Cela va être un hack, mais essayez de lancer un nouveau thread en quelques centaines de millisecondes (IIRC: 300-400 semblait fonctionner pour moi, mais vous aurez besoin de bricoler) qui ouvre votre ProgressDialog et lance tout ce dont vous avez besoin par exemple réseau IO). Quelque chose comme ça:

@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
}
41
Jeremy Logan

J'utilise Android version 2.1 avec API niveau 7. J'ai été confronté à ce problème (ou à un problème similaire) et résolu en utilisant ceci:

Dialog dialog = new Dialog(this);

au lieu de cela:

Dialog dialog = new Dialog(getApplicationContext());

J'espère que cela t'aides :)

127
Taner

Pour moi a changé 

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

à

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

Ce qui est étrange, c’est que le premier se trouve dans le didacticiel de Google et que les gens reçoivent une erreur à ce sujet.

64
wtk

Je ne pense pas qu'il s'agisse d'un problème de synchronisation lié à un contexte d'application nul

Essayez d'étendre l'application dans votre application (ou utilisez-la si vous en avez déjà une)

public class MyApp extends Application

Rendre l'instance disponible en tant que singleton privé. C'est jamais nul

private static MyApp appInstance;

Faire un assistant statique dans MyApp (qui utilisera le singleton)

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

BOOM !!

Consultez également la réponse de l'ingénieur Android ici: WindowManager $ BadTokenException

Une des causes de cette erreur est peut-être une tentative d’affichage d’une application fenêtre/dialogue à travers un contexte qui n'est pas une activité.

Maintenant, je suis d'accord, cela n'a pas de sens que la méthode prenne un paramètre Context, au lieu de Activity.

23
alienjazzcat

Après avoir lu les réponses ci-dessus, j’ai trouvé que, pour ma situation, ce qui suit a résolu le problème.

Cela a jeté l'erreur

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

Sur la base des réponses précédentes suggérant que le contexte était incorrect, j'ai modifié la méthode getApplicationContext () pour extraire le contexte de la vue transmise aux boutons de la méthode onClick.

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

Je ne comprends pas tout à fait le fonctionnement de Java, donc je peux me tromper, mais je suppose que dans mon cas particulier, la cause pourrait être liée au fait que le fragment ci-dessus a été défini dans une classe Abstract Activity hérité et utilisé par de nombreuses activités, peut-être que cela a contribué au fait que getApplicationContext () ne renvoie pas un contexte valide? (Juste une supposition). 

10
Emile

Je crée une vue cartographique avec des superpositions détaillées. Je créais mon calque détaillé comme ceci depuis mon mapActivity:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

J'ai constaté que j'obtiendrais l'exception "Android.view.WindowManager $ BadTokenException: impossible d'ajouter une fenêtre - le jeton null n'est pas pour une application" lorsque la méthode onTap de mon itemizedoverlay était déclenchée (lorsque l'emplacement est exploité dans la vue map).

J'ai trouvé que si je passais simplement 'this' à la place de 'getApplicationContext ()' à mon constructeur, le problème disparaissait. Cela semble appuyer la conclusion de alienjazzcat. bizarre.

6
cipherz

Pour les activités affichées dans TabActivities, utilisez getParent ()

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

au lieu de 

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

Pour Android 2.2
Utilisez ce code:

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

au lieu de ce code:

// 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);

Remarque: ma boîte de dialogue personnalisée est créée en dehors de la méthode activity.onCreateDialog(int dialogId).

3
jm_java

Essayer -

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

Avait un problème similaire avec (compatibilité) Fragments dans lequel l'utilisation d'un getActivity() dans ProgressDialog.show() le bloque. Je conviens que c'est à cause du timing.

Une solution possible:

mContext = getApplicationContext();

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

à la place d'utiliser

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

Placez le mContext le plus tôt possible pour lui donner plus de temps pour saisir le contexte. Il n'y a toujours aucune garantie que cela fonctionne, cela réduit simplement les risques d'accident. Si cela ne fonctionne toujours pas, vous devrez recourir au hack de la minuterie (ce qui peut causer d'autres problèmes de minutage, tels que le fait de fermer la boîte de dialogue ultérieurement). 

Bien sûr, si vous pouvez utiliser this ou ActivityName.this, c'est plus stable car this pointe déjà sur quelque chose. Mais dans certains cas, comme avec certaines architectures Fragment, ce n'est pas une option.

2
Muz

(Pour les références futures)

Je pense que c'est parce qu'il y a des différences de contexte d'application et de contexte d'activité, comme expliqué ici: http://www.doubleencore.com/2013/06/context/

Ce qui signifie que nous ne pouvons pas afficher de dialogue à l'aide du contexte d'application. C'est tout.

2
vtloc

Pour utiliser les dialogues dans les activités, procédez comme suit:

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
     //...
}

Pour utiliser des dialogues à l'intérieur de fragments, procédez comme suit:

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;
}

C'est ça ^ _ ^

2
blueware

Pour résoudre ce problème, j'ai créé une classe de base pour toutes mes activités où je stockais des données globales. Dans la première activité, j'ai enregistré le contexte dans une variable de ma classe de base, comme suit:

Classe de base

public static Context myucontext; 

Première activité dérivée de la classe de base

mycontext = this

Ensuite, j'utilise mycontext au lieu de getApplicationContext lors de la création de boîtes de dialogue. 

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

Si vous appelez ProgressDialog.show () dans un fragment, la conversion du mContext en activité a fonctionné pour moi.

     ProgressDialog pd = new ProgressDialog((Activity) mContext);
1
Dale Julian

si vous avez un problème avec le groupe Activité, n'utilisez pas ceci . PARENT est un élément statique du groupe d'activités parent.

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

au lieu de 

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

C’est un problème courant… .. Utilisez this au lieu de getApplicationContext()

0
Atul Kumar

Une boîte de dialogue est toujours créée et affichée dans le cadre d’une activité. Vous devez passer dans un contexte d'activité au lieu du contexte d'application.

http://developer.Android.com/guide/topics/ui/dialogs.html#ShowingADialog

0
Sam

J'ai implémenté Alert Dialog pour une exception avec la vue d'activité en cours. Chaque fois que j'avais donné ceci

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

Étant donné la même fenêtre Exception.J'ai écrit du code pour l'alerte à partir de onCreate (). Si simple, j'ai utilisé context = this; après l'instruction setContentView() dans la méthode onCreate(). Variable de contexte pris comme aussi global que Context context;

L'échantillon de code est

static Context context;

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


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

        context = this;
.......

Méthode d'alerte Sample is

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

Cela fonctionne bien pour moi.En fait, j'ai recherché cette erreur sur StackOverflow, j'ai trouvé cette requête.Après avoir lu toutes les réponses de ce message, j'ai essayé cette méthode, donc ça marche. Je pensais que c'était une solution simple pour surmonter l'exception.

Merci, Rajendar

0
Rajendar