web-dev-qa-db-fra.com

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

De mon activity principal, j'ai besoin d'appeler une classe interne et dans une méthode de la classe, je dois montrer AlertDialog. Après l'avoir rejeté, lorsque vous appuyez sur le bouton OK, transmettez-le à Google Play pour qu'il l'achète.

Les choses fonctionnent parfaitement la plupart du temps, mais pour quelques utilisateurs, il se bloque sur builder.show() et je peux voir "Android.view.WindowManager$BadTokenException: Impossible d’ajouter une fenêtre "à partir du journal du crash. Suggérez-le.

Mon code est à peu près comme ça:

public class classname1 extends Activity{

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

    //call the <className1> class to execute
  }

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

    protected String doInBackground(String... params) {}

    protected void onPostExecute(String result){
      if(page.contains("error")) 
      {
        AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
        builder.setCancelable(true);
        builder.setMessage("");
        builder.setInverseBackgroundForced(true);
        builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int whichButton){
            dialog.dismiss();
            if(!<condition>)
            {
              try
              {
                String pl = ""; 

                mHelper.<flow>(<class>.this, SKU, RC_REQUEST, 
                  <listener>, pl);
              }

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

        builder.show();
      }
    }
  }
}

J'ai également vu l'erreur dans une autre alerte où je ne transfère pas à un autre activity. C'est simple comme ça:

AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
    builder.setCancelable(true);

    //if successful
    builder.setMessage(" ");
    builder.setInverseBackgroundForced(true);
    builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton){
            // dialog.dismiss();
                   }
    });
    builder.show();
}
101
MSIslam
Android.view.WindowManager$BadTokenException: Unable to add window"

Problème:

Cette exception se produit lorsque l'application tente d'avertir l'utilisateur à partir du thread en arrière-plan (AsyncTask) en ouvrant une boîte de dialogue.

Si vous essayez de modifier l'interface utilisateur à partir du thread d'arrière-plan (généralement à partir de onPostExecute () de AsyncTask) et si l'activité entre dans l'étape de fin), appelez explicitement finish (), l'utilisateur appuyant sur le bouton d'accueil ou de retour ou le nettoyage de l'activité effectué par Android alors vous obtenez cette erreur.

Raison:

La raison de cette exception est que, comme l'indique le message d'exception, l'activité est terminée, mais que vous essayez d'afficher une boîte de dialogue avec un contexte de l'activité terminée. Puisqu'il n'y a pas de fenêtre pour que la boîte de dialogue affiche le Android runtime lève cette exception.

Solution:

Utilisez la méthode isFinishing() qui est appelée par Android pour vérifier si cette activité est en train de se terminer: que ce soit l'appel explicite de finish () ou le nettoyage de l'activité effectué par Android. En utilisant cette méthode, il est très facile d'éviter d'ouvrir la boîte de dialogue à partir du fil de fond lorsque l'activité est terminée.

Conservez également un weak reference pour l'activité (et non une référence forte afin que l'activité puisse être détruite une fois que vous n'en avez plus besoin) et vérifiez si l'activité ne se termine pas avant d'exécuter une interface utilisateur utilisant cette référence d'activité (c'est-à-dire en affichant une boîte 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:

jetons de fenêtre:

Comme son nom l'indique, un jeton de fenêtre est un type spécial de jeton de reliure que le gestionnaire de fenêtres utilise pour identifier de manière unique une fenêtre du système. Les jetons de fenêtre sont importants pour la sécurité car ils empêchent les applications malveillantes d’attirer les utilisateurs par-dessus les fenêtres d’autres applications. Le gestionnaire de fenêtres protège contre cela en exigeant que les applications transmettent le jeton de fenêtre de leur application dans le cadre de chaque demande d'ajout ou de suppression d'une fenêtre. Si les jetons ne correspondent pas, le gestionnaire de fenêtres rejette la demande et lève une exception BadTokenException. Sans jetons de fenêtre, cette étape d'identification indispensable ne serait pas possible et le gestionnaire de fenêtres ne pourrait pas se protéger contre les applications malveillantes.

n scénario du monde réel:

Lorsqu'une application démarre pour la première fois, ActivityManagerService crée un type spécial de jeton de fenêtre appelé jeton de fenêtre d'application, qui identifie de manière unique la fenêtre de conteneur de niveau supérieur de l'application. Le gestionnaire d'activités donne ce jeton à l'application et au gestionnaire de fenêtres, et l'application l'envoie au gestionnaire de fenêtres chaque fois qu'il souhaite ajouter une nouvelle fenêtre à l'écran. Cela garantit une interaction sécurisée entre l'application et le gestionnaire de fenêtres (en rendant impossible l'ajout de fenêtres par-dessus d'autres applications), et facilite également la tâche du gestionnaire d'activités d'envoyer des demandes directes au gestionnaire de fenêtres.

241
Ritesh Gune

J'ai eu un dialogue montrant la fonction:

void showDialog(){
    new AlertDialog.Builder(MyActivity.this)
    ...
    .show();
}

Je recevais cette erreur et je devais juste vérifier isFinishing() avant d'appeler cette fonction de dialogue.

if(!isFinishing())
    showDialog();
18
Jemshit Iskenderov

La raison possible est le contexte du dialogue d'alerte. Vous pouvez avoir terminé cette activité pour essayer d’ouvrir dans ce contexte mais qui est déjà fermé. Essayez de changer le contexte de cette boîte de dialogue en votre première activité, car elle ne sera pas terminée avant la fin.

par exemple

plutôt que cela.

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

essayez d'utiliser

AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();
9
Raghavendra
  • 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();
    }
    
3
moh.sukhni

Essaye ça :

    public class <class> extends Activity{

    private AlertDialog.Builder builder;

    public void onCreate(Bundle savedInstanceState) {
                    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
                    super.onCreate(savedInstanceState);

                setContentView(R.layout.<view>); 

                builder = new AlertDialog.Builder(<class>.this);
                builder.setCancelable(true);
                builder.setMessage(<message>);
                builder.setInverseBackgroundForced(true);

        //call the <className> class to execute
}

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

    protected String doInBackground(String... params) {

    }
    protected void onPostExecute(String result){
        if(page.contains("error")) //when not subscribed
        {   
           if(builder!=null){
                builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton){
                    dialog.dismiss();
                        if(!<condition>)
                        {
                        try
                        {
                        String pl = ""; 

                        mHelper.<flow>(<class>.this, SKU, RC_REQUEST, 
                        <listener>, pl);
                        }

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

            builder.show();
        }
    }

}
}
0
pathe.kiran

J'essaye ce qu'il a résolu.

 AlertDialog.Builder builder = new AlertDialog.Builder(
                   this);
            builder.setCancelable(true);
            builder.setTitle("Opss!!");

            builder.setMessage("You Don't have anough coins to withdraw. ");
            builder.setMessage("Please read the Withdraw rules.");
            builder.setInverseBackgroundForced(true);
            builder.setPositiveButton("OK",
                    (dialog, which) -> dialog.dismiss());
            builder.create().show();
0
himanshu kumar

Je crée un dialogue dans onCreate et 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();

J'étais en train de terminer l'activité à domicile 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();
0
Siddharth