android alertdialog - 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




builder tutorial (20)

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.

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


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


dans Activity, utilisez simplement:

MyActivity.this

en Fragment:

getActivity();

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 utilisez un fragment et utilisez un message AlertDialog / Toast , utilisez getActivity() dans le paramètre context.

A travaillé pour moi.

À votre santé!


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.


Votre dialogue ne doit pas être un "objet de longue durée qui a besoin d'un contexte". La documentation est source de confusion. Fondamentalement, si vous faites quelque chose comme:

static Dialog sDialog;

(notez le statique )

Ensuite, dans une activité quelque part que vous avez fait

 sDialog = new Dialog(this);

Vous feriez probablement la fuite l'activité originale pendant une rotation ou semblable qui détruirait l'activité. (Sauf si vous nettoyez dans onDestroy, mais dans ce cas, vous ne rendrez 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 boîtes de dialogue. Donc, quelque chose comme ça:

Dialog mDialog;

...

mDialog = new Dialog(this);

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


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

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

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:


Essayez d'utiliser le contexte d'une activité qui sera sous le dialogue. Mais soyez prudent lorsque vous utilisez ce mot clé, car cela ne fonctionnera pas à chaque fois.

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

Je n'ai trouvé cette information d'aucun document mais en essayant. Ceci est ma solution sans antécédents forts, Si quelqu'un avec une meilleure connaissance, n'hésitez pas à commenter.


Petit piratage: vous pouvez éviter 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();
    }
    ...
}

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


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

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.


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


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" />

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

comme ça

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

Dans mon cas, travaillez:

this.getContext();

J'utilisais ProgressDialog dans un fragment et getActivity().getApplicationContext() cette erreur en passant getActivity().getApplicationContext() tant que paramètre constructeur. Le changer en getActivity().getBaseContext() ne fonctionnait pas non plus.

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

progressDialog = new ProgressDialog(getActivity());


YourApplication \ app \ build \ outputs \ apk





android android-alertdialog android-context builder