android - alertdialog builder tutorial




Lancement de boîte de dialogue "Impossible d'ajouter une fenêtre-le token null n'est pas pour une application" avec getApplication() comme contexte (16)

Mon activité tente de créer un objet AlertDialog qui nécessite un contexte en tant que paramètre. Cela fonctionne comme prévu si j'utilise:

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

Cependant, je me méfie de l'utilisation de "ceci" comme contexte en raison du risque de fuite de mémoire lorsque l'activité est détruite et recréée même pendant quelque chose de simple comme une rotation d'écran. D'un article connexe sur le blog du développeur Android :

Il existe deux manières 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 les classes internes et leur référence implicite à la classe externe peuvent être tout aussi dangereuses. La deuxième solution consiste à utiliser le contexte d'application. Ce contexte va vivre aussi longtemps que votre application est en vie et ne dépend pas du cycle de vie des activités. Si vous envisagez de conserver des objets de longue durée nécessitant un contexte, souvenez-vous de l'objet d'application. Vous pouvez l'obtenir facilement en appelant Context.getApplicationContext () ou Activity.getApplication ().

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

"Impossible d'ajouter la fenêtre - le jeton null n'est pas pour une application"

par références: 1 , 2 , 3 , etc.

Donc, cela devrait-il vraiment être considéré comme un "bug", puisque nous sommes officiellement conseillé d'utiliser Activity.getApplication() et pourtant il ne fonctionne pas comme annoncé?

Jim


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


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

Bien qu'il ne soit pas explicitement indiqué partout où je le sais, il semble que vous ayez renvoyé la boîte de dialogue dans OnClickHandlers juste pour cela.


Dans l' Activity sur le clic du bouton montrant une boîte de dialogue

Dialog dialog = new Dialog(MyActivity.this);

A travaillé pour moi.


Dans mon cas, travaillez:

this.getContext();

Essayez getParent () à l'endroit du contexte d'argument comme nouveau AlertDialog.Builder (getParent ()); J'espère que ça va marcher, ça a marché pour moi.


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

this.getActivity().getWindow().getContext() dans le rappel onCreate des fragments.


Je pense que cela peut arriver aussi si vous essayez d'afficher un dialogue à partir d'un thread qui n'est pas le thread principal de l'interface utilisateur.

Utilisez runOnUiThread () dans ce cas.


Ou une autre possibilité est de créer un dialogue 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();
        }
    }
}

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

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

A travaillé pour moi.

À votre santé!


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


Vous avez correctement identifié le problème lorsque vous avez dit "... pour le AlertDialog () ni getApplicationContext () ni getApplication () n'est acceptable en tant que Contexte, car il lance l'exception: 'Impossible d'ajouter la fenêtre - token null n'est pas 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 () retournent un contexte d'application).

Voici comment vous obtenez le contexte d'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 sont pas un problème intrinsèque à la référence "this", qui est la référence d'un objet à lui-même (c'est-à-dire référence à la mémoire allouée pour stocker les données de l'objet). Cela arrive à toute mémoire allouée pour laquelle le Garbage Collector (GC) est incapable de libérer après que la mémoire allouée a survécu à sa durée de vie utile.

La plupart du temps, lorsqu'une variable est hors de 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, disons "x", persiste même après que l'objet a survécu à sa durée de vie utile. La mémoire allouée sera donc perdue tant que "x" contient une référence car GC ne libérera pas la mémoire tant que cette mémoire est encore 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 un tel cas, le GC ne libérera pas la mémoire tant que toutes les références à cette mémoire n'auront pas été supprimées.

Pour éviter les fuites de mémoire, vérifiez votre code pour les erreurs logiques qui entraînent une référence indéfinie de la mémoire allouée par "this" (ou d'autres références). N'oubliez pas de vérifier également 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 embêtantes:


Vous pouvez continuer à utiliser getApplicationContext() , mais avant de l'utiliser, vous devez ajouter cet indicateur: 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" />

dans Activity, utilisez simplement:

MyActivity.this

en Fragment:

getActivity();

this n'a pas fonctionné pour moi, mais MyActivityName.this . J'espère que cela aidera tous ceux qui ne pourraient pas obtenir this travail.







builder