Android 1.6: «android.view.WindowManager $ BadTokenException: impossible d'ajouter une fenêtre - le token null n'est pas pour une application»

303

J'essaie d'ouvrir une fenêtre de dialogue, mais chaque fois que j'essaye de l'ouvrir, elle lance cette exception:

Uncaught handler: thread main exiting due to uncaught exception
android.view.WindowManager$BadTokenException: 
     Unable to add window -- token null is not for an application
  at android.view.ViewRoot.setView(ViewRoot.java:460)
  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
  at android.app.Dialog.show(Dialog.java:238)
  at android.app.Activity.showDialog(Activity.java:2413)

Je le crée en appelant showDialogavec l'ID de l'affichage. Le onCreateDialoggestionnaire se connecte correctement et je peux le parcourir sans problème, mais je l'ai joint car il semble que je manque quelque chose:

@Override
public Dialog onCreateDialog(int id)
{
    Dialog dialog;
    Context appContext = this.getApplicationContext();
    switch(id)
    {
        case RENAME_DIALOG_ID:
            Log.i("Edit", "Creating rename dialog...");
            dialog = new Dialog(appContext);
            dialog.setContentView(R.layout.rename);
            dialog.setTitle("Rename " + noteName);
            break;
        default:
            dialog = null;
            break;
    }
    return dialog;      
}

Y a-t-il quelque chose qui manque à cela? Certaines questions ont évoqué ce problème lors de la création d'une boîte de dialogue à partir de onCreate, ce qui se produit car l'activité n'est pas encore créée, mais cela provient d'un appel à partir d'un objet de menu, et la appContextvariable semble être correctement remplie dans le débogueur.

Dan Monego
la source

Réponses:

609

Au lieu de: Context appContext = this.getApplicationContext(); vous devez utiliser un pointeur vers l'activité dans laquelle vous vous trouvez (probablement this).

J'ai également été mordu par cela aujourd'hui, la partie ennuyeuse est le getApplicationContext()mot à mot de developer.android.com :(

Torp
la source
2
Il est également signalé comme un bug (bien que ce ne soit pas lorsque l'utilisateur a posté la question): code.google.com/p/android/issues/detail?id=11199
Raymond Martineau
63
Juste au cas où cela aiderait quelqu'un - utilisez myActivity.this comme contexte dans une boîte de dialogue.
Rab Ross
13
Cette question et réponse a 3 ans en 2 jours. J'ai toujours une réputation, donc je suppose que Google n'a toujours pas corrigé ses documents ...
Torp
2
Ce problème a été corrigé dans ( developer.android.com/guide/topics/ui/dialogs.html )
Martin Marconcini
6
Nous sommes en avril 2016, et cette exception fait toujours planter l'application au démarrage de la boîte de dialogue.
Yogesh Seralia
78

Vous ne pouvez pas afficher une fenêtre / boîte de dialogue d'application via un contexte qui n'est pas une activité. Essayez de transmettre une référence d'activité valide

Samuh
la source
Comment? J'ai essayé activity.thiset en activity.getBaseContext()vain. De l'aide?
Darpan
3
Je l'ai. Saisissez directement le nom de votre activité. Sans .this.
Darpan
45

Idem sur la chose getApplicationContext.

Les documents sur le site Android disent de l'utiliser, mais cela ne fonctionne pas ... grrrrr :-P

Faites juste:

dialog = new Dialog(this); 

"ceci" est généralement votre activité à partir de laquelle vous démarrez la boîte de dialogue.

kenyee
la source
43

Les documents Android suggèrent d'utiliser getApplicationContext ();

mais cela ne fonctionnera pas au lieu d'utiliser cette activité lors de l'instanciation d'AlertDialog.Builder ou AlertDialog ou Dialog ...

Ex:

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

ou

AlertDialog.Builder builder = new  AlertDialog.Builder((Your Activity).this);
Pradeep
la source
Cela m'a aidé massivement. J'essayais de créer une boîte de dialogue à partir d'une autre boîte de dialogue et j'avais simplement "AlertDialog.Builder (this);" donnait une erreur. Merci!
EHarpham
(ActivityName.this) est particulièrement utile lorsque vous essayez de créer une boîte de dialogue à l'intérieur d'un clic sur un bouton
RmK
Mon problème est que je construis un ProgressDialog à l'intérieur d'un AlertDialog à l'intérieur d'un adaptateur ... Je ne peux pas le faire fonctionner.
Martin Erlic
17

Au lieu de getApplicationContext(), utilisez simplementActivityName.this

mahbub_siddique
la source
13

J'ai eu un problème similaire où j'avais une autre classe quelque chose comme ça:

public class Something {
  MyActivity myActivity;

  public Something(MyActivity myActivity) {
    this.myActivity=myActivity;
  }

  public void someMethod() {
   .
   .
   AlertDialog.Builder builder = new AlertDialog.Builder(myActivity);
   .
   AlertDialog alert = builder.create();
   alert.show();
  }
}

A bien fonctionné la plupart du temps, mais parfois il s'est écrasé avec la même erreur. Ensuite, je me rends compte que MyActivityj'avais en ...

public class MyActivity extends Activity {
  public static Something something;

  public void someMethod() {
    if (something==null) {
      something=new Something(this);
    }
  }
}

Parce que je tenais l'objet en tant que static, une deuxième exécution du code contenait toujours la version originale de l'objet, et faisait donc toujours référence à l'originalActivity , qui n'existait plus.

Erreur stupide et stupide, d'autant plus que je n'avais vraiment pas besoin de tenir l'objet comme staticen premier lieu ...

T.Hawk
la source
12

Il suffit de le changer en

AlertDialog.Builder alert_Categoryitem = 
    new AlertDialog.Builder(YourActivity.this);

Au lieu de

AlertDialog.Builder alert_Categoryitem = 
    new AlertDialog.Builder(getApplicationContext());
Satheesh
la source
9

Une autre solution consiste à définir le type de fenêtre sur une boîte de dialogue système:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

Cela nécessite l' SYSTEM_ALERT_WINDOWautorisation:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

Comme le disent les docs:

Très peu d'applications devraient utiliser cette autorisation; ces fenêtres sont destinées à une interaction au niveau du système avec l'utilisateur.

Il s'agit d'une solution que vous ne devez utiliser que si vous avez besoin d'une boîte de dialogue qui n'est pas attachée à une activité.

Anubian Noob
la source
C'est maintenant un indicateur obsolète du niveau API 26. Parce qu'il permet au développeur de jouer avec une fenêtre système qui n'est pas bonne du point de vue de l'utilisateur.
CopsOnRoad
4

Ne pas utiliser getApplicationContext() pour déclarer dialouge

Utilisez toujours thisou votreactivity.this

Jinu
la source
2

Pour les boîtes de dialogue imbriquées, ce problème est très courant, il fonctionne lorsque

AlertDialog.Builder mDialogBuilder = new AlertDialog.Builder(MyActivity.this);

est utilisé au lieu de

mDialogBuilder = new AlertDialog.Builder(getApplicationContext);

cette alternative.

mifthi
la source
2

Cela a fonctionné pour moi ...

new AlertDialog.Builder(MainActivity.this)
        .setMessage(Html.fromHtml("<b><i><u>Spread Knowledge Unto The Last</u></i></b>"))
        .setCancelable(false)
        .setPositiveButton("Dismiss",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                    }
                }).show();

Utilisation

ActivityName.this
Suyog Gunjal
la source
0

Vous pouvez également le faire

public class Example extends Activity {
    final Context context = this;
    final Dialog dialog = new Dialog(context);
}

Cela a fonctionné pour moi !!

Metalhead1247
la source
0

Comme il est dit, vous avez besoin d'une activité comme contexte pour la boîte de dialogue, utilisez "YourActivity.this" pour un contexte statique ou vérifiez ici comment utiliser un dynamique en mode sans échec

Hugo
la source
0

Essayez de réinitialiser dialogle type de fenêtre sur

WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

N'oubliez pas d'utiliser l'autorisation android.permission.SYSTEM_ALERT_WINDOW

hopetribe
la source
0
public class Splash extends Activity {

    Location location;
    LocationManager locationManager;
    LocationListener locationlistener;
    ImageView image_view;
    ublic static ProgressDialog progressdialog;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash);
        progressdialog = new ProgressDialog(Splash.this);
           image_view.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                        locationManager.requestLocationUpdates("gps", 100000, 1, locationlistener);
                        Toast.makeText(getApplicationContext(), "Getting Location plz wait...", Toast.LENGTH_SHORT).show();

                            progressdialog.setMessage("getting Location");
                            progressdialog.show();
                            Intent intent = new Intent(Splash.this,Show_LatLng.class);
//                          }
        });
    }

Texte ici: -
utilisez ceci pour obtenir le activitycontexte pourprogressdialog

 progressdialog = new ProgressDialog(Splash.this);

ou progressdialog = new ProgressDialog(this);

utilisez-le pour obtenir le contexte d'application pour BroadcastListener pas pour progressdialog.

progressdialog = new ProgressDialog(getApplicationContext());
progressdialog = new ProgressDialog(getBaseContext());
Faisal Ashraf
la source
0

Le meilleur moyen et le plus sûr d'afficher un «ProgressDialog» dans une AsyncTask, pour éviter les problèmes de fuite de mémoire est d'utiliser un «Handler» avec Looper.main ().

    private ProgressDialog tProgressDialog;

puis dans le «onCreate»

    tProgressDialog = new ProgressDialog(this);
    tProgressDialog.setMessage(getString(R.string.loading));
    tProgressDialog.setIndeterminate(true);

Vous avez maintenant terminé avec la partie configuration. Appelez maintenant 'showProgress ()' et 'hideProgress ()' dans AsyncTask.

    private void showProgress(){
        new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                tProgressDialog.show();
            }
        }.sendEmptyMessage(1);
    }

    private void hideProgress(){
        new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                tProgressDialog.dismiss();
            }
        }.sendEmptyMessage(1);
    }
Sankar Behera
la source