Lancement de la boîte de dialogue "Impossible d'ajouter une fenêtre – le numéro de token n'est pas une application" avec getApplication () en tant que contexte

Mon activité essaie de créer un AlertDialog qui requiert un contexte comme paramètre. Cela fonctionne comme prévu si j'utilise:

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

Cependant, je suis méfiant d'utiliser «ce» comme un contexte en raison de la possibilité de fuites de mémoire lorsque l'activité est détruite et recréée même pendant quelque chose de simple comme une rotation d'écran. À partir d'une publication connexe sur le blog du développeur Android :

  • Comment accéder à une base de données sqlite existante dans Android?
  • Définir un dossier personnalisé Gestionnaire de téléchargement d'Android
  • Comment fonctionne un android: attr style?
  • Éviter la perte de données en raison d'une interruption lors de l'enregistrement de fichiers sur Android?
  • Android activant wifi par programme
  • Processus d'arrière-plan pour analyser l'emplacement de l'utilisateur à intervalles réguliers et mettre à jour la base de données locale même lorsque l'application n'est pas ouverte
  • Il existe deux façons simples d'éviter les fuites de mémoire liées au contexte. Le plus évident est d'éviter d'échapper au contexte en dehors de sa propre portée. L'exemple ci-dessus montre le cas d'une référence statique mais des classes internes et leur référence implicite à la classe externe peut être tout aussi dangereux. La deuxième solution consiste à utiliser le contexte de l'application. Ce contexte va vivre tant que votre application est en vie et ne dépend pas du cycle de vie des activités. Si vous prévoyez de garder des objets à longue durée de vie qui nécessitent un contexte, n'oubliez pas l'objet de l'application. Vous pouvez l'obtenir facilement en appelant Context.getApplicationContext () ou Activity.getApplication ().

    Mais pour AlertDialog() ni getApplicationContext() ou getApplication() n'est acceptable en tant que contexte, car il lance l'exception:

    "Impossible d'ajouter une fenêtre – token null n'est pas pour une application"

    Par référence: 1 , 2 , 3 , etc.

    Donc, est-ce que cela devrait être considéré comme un "bogue", car on nous conseille officiellement d'utiliser Activity.getApplication() et pourtant il ne fonctionne pas comme annoncé?

    Jim

    22 Solutions collect form web for “Lancement de la boîte de dialogue "Impossible d'ajouter une fenêtre – le numéro de token n'est pas une application" avec getApplication () en tant que contexte”

    Au lieu de getApplicationContext() , utilisez seulement ActivityName.this .

    L'utilisation de " this " n'a pas fonctionné pour moi, mais " MyActivityName.this " a fait. J'espère que cela aidera quiconque ne pourrait pas obtenir " this " pour fonctionner.

    Vous pouvez continuer à utiliser getApplicationContext() , mais avant l'utilisation, vous devez ajouter ce drapeau: dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT) et l'erreur ne s'affichera pas.

    Ajoutez l'autorisation suivante à votre manifeste:

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

    Votre boîte de dialogue ne doit pas être un «objet à longue durée de vie qui a besoin d'un contexte». La documentation confondue. Fondamentalement, si vous faites quelque chose comme:

     static Dialog sDialog; 

    (Notez la statique )

    Ensuite, dans une activité où vous avez fait

      sDialog = new Dialog(this); 

    Vous risqueriez de filtrer l'activité initiale pendant une rotation ou similaire qui détruirait l'activité. (Sauf si vous nettoyez sur Destroy, mais dans ce cas, vous ne feriez probablement pas l'objet Dialog statique)

    Pour certaines structures de données, il serait logique de les rendre statiques et basées sur le contexte de l'application, mais généralement pas pour les choses liées à l'interface utilisateur, comme les dialogues. Donc, quelque chose comme ça:

     Dialog mDialog; ... mDialog = new Dialog(this); 

    Est bon et ne devrait pas fuir l'activité car mDialog serait libéré avec l'activité car elle n'est pas statique.

    Vous ne pouvez pas afficher une window/dialog application via un contexte qui n'est pas une activité ou un service . Essayez de passer une référence d'activité valide

    Dans Activity sur le bouton d'un bouton montrant une boîte de dialogue

     Dialog dialog = new Dialog(MyActivity.this); 

    J'ai travaillé pour moi.

    J'ai dû envoyer mon contexte à travers un constructeur sur un adaptateur personnalisé affiché dans un fragment et a eu ce problème avec getApplicationContext (). Je l'ai résolu avec:

    this.getActivity().getWindow().getContext() dans les fragments ' onCreate callback.

    Petit hack: vous pouvez empêcher de détruire l'activité par GC (Bien sûr, vous ne devriez pas le faire, mais cela peut aider dans certaines situations):

     public class PostActivity extends Activity { ... private Context contextForDialog = null; ... public void onCreate(Bundle savedInstanceState) { ... contextForDialog = this; } ... private void showAnimatedDialog() { mSpinner = new Dialog(contextForDialog); mSpinner.setContentView(new MySpinner(contextForDialog)); mSpinner.show(); } ... } 

    Si vous utilisez un fragment et que vous utilisez le message AlertDialog / Toast, utilisez getActivity () dans le paramètre de contexte.

    comme ça

     ProgressDialog pdialog; pdialog = new ProgressDialog(getActivity()); pdialog.setCancelable(true); pdialog.setMessage("Loading ...."); pdialog.show(); 

    Vous avez correctement identifié le problème lorsque vous dites "… pour AlertDialog (), ni getApplicationContext () ou getApplication () n'est acceptable en tant que contexte, car il jette l'exception: 'Impossible d'ajouter une fenêtre – token null n'est pas pour une application'"

    Pour créer une boîte de dialogue, vous avez besoin d'un contexte d'activité ou d'un contexte de service , et non d'un contexte d'application (à la fois getApplicationContext () et getApplication () renvoie un contexte d'application).

    Voici comment vous obtenez le contexte de l' activité :

    (1) Dans une activité ou un service:

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

    (2) Dans un Fragment: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

    Les fuites de mémoire ne constituent pas un problème intrinsèque à la référence "this", qui est la référence d'un objet (c'est-à-dire la référence à la mémoire allouée réelle pour stocker les données de l'objet). Il arrive à n'importe quelle mémoire allouée pour laquelle le Collecteur de Garbage (GC) est incapable de libérer après que la mémoire allouée ait dépassé sa durée de vie utile.

    La plupart du temps, lorsqu'une variable sort de la portée, la mémoire sera récupérée par le GC. Cependant, des fuites de mémoire peuvent se produire lorsque la référence à un objet détenu par une variable, disent "x", persiste même après que l'objet a dépassé sa durée de vie utile. La mémoire allouée sera donc perdue aussi longtemps que «x» contient une référence parce que GC ne libère pas la mémoire aussi longtemps que cette mémoire est toujours référencée. Parfois, les fuites de mémoire ne sont pas apparentes en raison d' une chaîne de références à la mémoire allouée. Dans ce cas, le GC ne libère pas la mémoire jusqu'à ce que toutes les références à cette mémoire aient été supprimées.

    Pour éviter les fuites de mémoire, vérifiez votre code pour les erreurs logiques qui font que la mémoire allouée doit être référencée indéfiniment par "ceci" (ou d'autres références). N'oubliez pas de consulter les références de chaîne. Voici quelques outils que vous pouvez utiliser pour vous aider à analyser l'utilisation de la mémoire et à trouver ces fuites de mémoire gênantes:

    • JRockit Mission Control

    • JProbe

    • YourKit

    • AD4J

    J'utilisais ProgressDialog dans un fragment et getActivity().getApplicationContext() cette erreur en passant getActivity().getApplicationContext() comme paramètre constructeur. En changeant pour getActivity().getBaseContext() n'a pas fonctionné non plus.

    La solution qui a fonctionné pour moi était de passer getActivity() ; c'est à dire

    progressDialog = new ProgressDialog(getActivity());

    Si vous êtes en dehors de l'activité, vous devez utiliser dans votre fonction "NameOfMyActivity.this" comme activité, par exemple:

     public static void showDialog(Activity activity) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage("Your Message") .setPositiveButton("Yes", dialogClickListener) .setNegativeButton("No", dialogClickListener).show(); } //Outside your Activity showDialog(NameOfMyActivity.this); 

    ajouter

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

    et

    "android.permission.SYSTEM_ALERT_WINDOW"/> en manifeste

    Cela fonctionne pour moi maintenant. Après même fermer et ouvrir l'application, je me suis donné l'erreur à ce moment-là.

    Si vous utilisez un fragment et que vous utilisez un message AlertDialog / Toast , utilisez getActivity() dans le paramètre de contexte.

    J'ai travaillé pour moi.

    À votre santé!

    Essayez d'utiliser le contexte d'une activité qui sera sous la boîte de dialogue. Mais soyez prudent lorsque vous utilisez le mot-clé "this", car cela ne fonctionnera pas chaque fois.

    Par exemple, si vous avez TabActivity comme hôte avec deux onglets, et chaque onglet est une autre activité, et si vous essayez de créer une boîte de dialogue à partir de l'un des onglets (activités) et si vous utilisez "ceci", vous obtiendrez une exception. Une boîte de dialogue devrait être connectée à une activité hôte qui héberge tout et visible. (Vous pouvez dire le contexte de l'activité parentale la plus visible)

    Je n'ai pas trouvé cette information à partir de n'importe quel document, mais en essayant. C'est ma solution sans fond fort, si quelqu'un connait mieux, n'hésitez pas à commenter.

    Utilisez MyDialog md = new MyDialog(MyActivity.this.getParent());

    Dans mon cas de travail:

     this.getContext(); 

    Essayez getParent () au lieu d'argument du contexte comme nouveau AlertDialog.Builder (getParent ()); J'espère que cela fonctionnera, cela a fonctionné pour moi.

    Je pense que cela peut arriver aussi bien si vous essayez de montrer une boîte de dialogue à partir d'un thread qui n'est pas le thread UI principal.

    Utilisez runOnUiThread () dans ce cas.

    Ou une autre possibilité est de créer Dialog comme suit:

     final Dialog dialog = new Dialog(new ContextThemeWrapper( this, R.style.MyThemeDialog)); 

    Pour les futurs lecteurs, cela devrait aider:

     public void show() { if(mContext instanceof Activity) { Activity activity = (Activity) mContext; if (!activity.isFinishing() && !activity.isDestroyed()) { dialog.show(); } } } 

    Après avoir examiné l'API, vous pouvez passer la boîte de dialogue de votre activité ou getActivity si vous êtes dans un fragment, puis le nettoyer avec le dialogue.dismiss () dans les méthodes de retour pour éviter les fuites.

    Bien qu'il ne soit pas explicitement énoncé n'importe où que je connaisse, il semble que vous ne répondez pas à la boîte de dialogue dans OnClickHandlers juste pour ce faire.

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.