135 votes

"android.view.WindowManager $ BadTokenException: impossible d'ajouter une fenêtre" sur buider.show ()

À partir de mon activité principale, j'ai besoin de faire appel à un intérieur de classe(où je fais appel de service web) et dans une méthode de la classe,j'ai besoin de montrer AlertDialg et écarter lorsque le bouton OK est pressée et à transmettre à Google Play pour l'achat.

Les choses fonctionnent parfaitement pour la plupart du temps, mais pour quelques utilisateurs, c'est de s'écraser sur le générateur.show() et je peux voir "android.vue.WindowManager$BadTokenException: Impossible d'ajouter la fenêtre" à partir de crash. S'il vous plaît suggérer.

Mon code sont à peu près comme ceci:

public class login extends Activity{

    public void onCreate(Bundle savedInstanceState) {
                this.requestWindowFeature(Window.FEATURE_NO_TITLE);
                super.onCreate(savedInstanceState);
                setContentView(R.layout.login); 

        new chkCubscription.execute("");
        }

    private class chkSubscription extends AsyncTask<String, Void, String>{

protected String doInBackground(String... params) {
//web service call
}
        protected void onPostExecute(String result){
          if(page.contains("error")) //when not subscribed
          {
             AlertDialog.Builder builder = new AlertDialog.Builder(login.this);
             builder.setCancelable(true);
             builder.setMessage(sucObject);
             builder.setInverseBackgroundForced(true);
             builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog, int whichButton){
                            dialog.dismiss();
 if(!mSubscribedToHomeApp)
    {
        try
        {
            String payload = ""; 

            mHelper.launchPurchaseFlow(login.this, SKU, RC_REQUEST, 
                    mPurchaseFinishedListener, payload);
        }

        catch(Exception e)
        {
            e.printStackTrace();
        }
          }  
         }
       });

        builder.show();
          }
        }
       }


    private class MyAsyncTask extends AsyncTask<String, Void, String>
    {
//Web Service call to check authentication
}
    }

J'ai également vu l'erreur dans une autre alerte où je ne suis pas transmettre à toute autre activité. C'est simple comme ceci:

AlertDialog.Builder builder = new AlertDialog.Builder(login.this);
    builder.setCancelable(true);
    JSONObject jObject = null;
    try {
        jObject = new JSONObject(page);
    } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }            

    if (page.contains("Error Message")){
        try {
            sucObject = jObject.getString("Error Message");
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    else{

    builder.setMessage(" ");
    builder.setInverseBackgroundForced(true);
    builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton){
            // dialog.dismiss();
                   }
        }
    });

    builder.show();

}

293voto

Ritesh Gune Points 6516
android.view.WindowManager$BadTokenException: Unable to add window"

Problème :

Cette exception se produit lorsque l'application tente d'avertir l'utilisateur de le thread d'arrière-plan (AsyncTask) par l'ouverture d'un Dialogue.

Si vous tentez de modifier l'INTERFACE utilisateur à partir du thread d'arrière-plan (généralement de onPostExecute() de AsyncTask) et si l'activité entre dans finition stade, c'est à dire) appelant explicitement finish(), utilisateur en appuyant sur la maison ou le bouton de retour ou de l'activité nettoyer faite par Android, vous obtenez ce erreur.

Raison :

La raison de cette exception est que, comme le message le dit, l'activité a fini, mais vous essayez d'afficher une boîte de dialogue avec contexte de l'activité. Depuis il n'y a pas de fenêtre pour l' boîte de dialogue pour afficher la android runtime lève cette exception.

Solution:

Utiliser isFinishing() méthode qui est appelée par Android pour vérifier si cette activité est dans le processus de finition: que ce soit explicite finish() appel ou de l'activité nettoyer faite par Android. En utilisant cette méthode, il est très facile d'éviter l'ouverture d'un dialogue à partir de thread d'arrière-plan lors de l'activité est de finition.

Également maintenir un weak reference de l'activité (et pas une forte de référence, de sorte que l'activité peut être détruit une fois n'est pas nécessaire) et vérifier si l'activité n'est pas de finition avant d'effectuer l'une de l'INTERFACE utilisateur à l'aide de cette l'activité de référence (c'est à dire afficher une boite de dialogue).

par exemple.

private class chkSubscription extends AsyncTask<String, Void, String>{

  private final WeakReference<login> loginActivityWeakRef;

  public chkSubscription (login loginActivity) {
    super();
    this.loginActivityWeakRef= new WeakReference<login >(loginActivity)
  }

  protected String doInBackground(String... params) {
    //web service call
  }

  protected void onPostExecute(String result) {
    if(page.contains("error")) //when not subscribed
    {
      if (loginActivityWeakRef.get() != null && !loginActivityWeakRef.get().isFinishing()) {
        AlertDialog.Builder builder = new AlertDialog.Builder(login.this);
        builder.setCancelable(true);
        builder.setMessage(sucObject);
        builder.setInverseBackgroundForced(true);

        builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int whichButton){
            dialog.dismiss();
          }
        });

        builder.show();
      }
    }
  }
}

Mise à jour :

Fenêtre Des Jetons:

Comme son nom l'indique, une fenêtre jeton est un type spécial de Liant jeton que le gestionnaire de fenêtre utilise pour identifier de manière unique une fenêtre dans le système. Fenêtre jetons sont importantes pour la sécurité parce qu'il est impossible pour les applications malveillantes dessiner sur les fenêtres de d'autres applications. Le gestionnaire de fenêtre protège contre cette par exigeant des applications de transmettre leur fenêtre de l'application jeton comme une partie de chaque demande d'ajouter ou de supprimer une fenêtre. Si les jetons ne sont pas match, le gestionnaire de fenêtre rejette la demande et jette un BadTokenException. Sans fenêtre jetons, ce nécessaire étape d'identification ne serait pas possible et le gestionnaire de fenêtre ne serait pas en mesure de se protéger contre les applications malveillantes.

 Un scénario concret:

Lorsqu'une application est lancée pour la première fois, le ActivityManagerService crée un type spécial de la fenêtre de jeton appelé une fenêtre d'application de jeton qui identifie de manière unique l' l'application conteneur de niveau supérieur de la fenêtre. Le gestionnaire d'activité donne ce jeton à la fois l'application et le gestionnaire de fenêtres, et la l'application envoie le jeton pour le gestionnaire de fenêtre à chaque fois qu'il veut pour ajouter une nouvelle fenêtre à l'écran. Cela garantit la sécurité de l'interaction entre l'application et le gestionnaire de fenêtre (en le faisant impossible d'ajouter des fenêtres au-dessus des autres applications), et aussi il est facile pour le gestionnaire d'activités pour faire des demandes directes de la gestionnaire de fenêtre.

3voto

moh.sukhni Points 871
  • d'abord, vous ne pouvez pas étendre AsyncTask sans remplacer doInBackground
  • Ensuite, essayez de créer AlterDailog à partir du générateur, puis appelez show ().

     private boolean visible = false;
    class chkSubscription extends AsyncTask<String, Void, String>
    {
    
        protected void onPostExecute(String result)
        {
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setCancelable(true);
            builder.setMessage(sucObject);
            builder.setInverseBackgroundForced(true);
            builder.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton)
                {
                    dialog.dismiss();
                }
            });
    
            AlertDialog myAlertDialog = builder.create();
            if(visible) myAlertDialog.show();
        }
    
        @Override
        protected String doInBackground(String... arg0)
        {
            // TODO Auto-generated method stub
            return null;
        }
    }
    
    
    @Override
    protected void onResume()
    {
        // TODO Auto-generated method stub
        super.onResume();
        visible = true;
    }
    
    @Override
    protected void onStop()
    {
        visible = false; 
        super.onStop();
    }
     

1voto

Siddharth Points 3828

Je crée un dialogue en onCreate et je l’utilise avec show et hide . Pour moi, la cause fondamentale n'était pas le rejet de onBackPressed , qui achevait l'activité Home .

 @Override
public void onBackPressed() {
new AlertDialog.Builder(this)
                .setTitle("Really Exit?")
                .setMessage("Are you sure you want to exit?")
                .setNegativeButton(android.R.string.no, null)
                .setPositiveButton(android.R.string.yes,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                Home.this.finish();
                                return;
                            }
                        }).create().show();
 

Je finissais l'activité à la maison onBackPressed sans fermer / fermer mes dialogues.

Lorsque j'ai rejeté mes dialogues, le crash a disparu.

 new AlertDialog.Builder(this)
                .setTitle("Really Exit?")
                .setMessage("Are you sure you want to exit?")
                .setNegativeButton(android.R.string.no, null)
                .setPositiveButton(android.R.string.yes,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                networkErrorDialog.dismiss() ;
                                homeLocationErrorDialog.dismiss() ;
                                currentLocationErrorDialog.dismiss() ;
                                Home.this.finish();
                                return;
                            }
                        }).create().show();
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X