it-swarm.com.de

Dialogfeld mit der Meldung "Fenster-Token null kann nicht für eine Anwendung hinzugefügt werden" mit getApplication () als Kontext

Meine Aktivität versucht, einen AlertDialog zu erstellen, für den ein Kontext als Parameter erforderlich ist. Dies funktioniert wie erwartet, wenn ich Folgendes verwende:

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

Ich bin jedoch misstrauisch, "dies" als Kontext zu verwenden, da es zu Speicherverlusten kommen kann, wenn die Aktivität zerstört und neu erstellt wird, selbst wenn es sich um eine einfache Bildschirmdrehung handelt. Aus einem verwandter Beitrag im Blog des Android Entwicklers :

Es gibt zwei einfache Möglichkeiten, um kontextbezogene Speicherverluste zu vermeiden. Am naheliegendsten ist es, den Kontext nicht außerhalb seines eigenen Bereichs zu verlassen. Das obige Beispiel zeigt den Fall einer statischen Referenz, aber innere Klassen und ihre implizite Referenz auf die äußere Klasse können gleichermaßen gefährlich sein. Die zweite Lösung besteht darin, den Anwendungskontext zu verwenden. Dieser Kontext bleibt so lange bestehen, wie Ihre Anwendung aktiv ist und hängt nicht vom Lebenszyklus der Aktivitäten ab. Wenn Sie langlebige Objekte behalten möchten, die einen Kontext benötigen, denken Sie an das Anwendungsobjekt. Sie können es leicht erhalten, indem Sie Context.getApplicationContext () oder Activity.getApplication () aufrufen.

Aber für die AlertDialog() ist weder getApplicationContext() noch getApplication() als Kontext akzeptabel, da sie die Ausnahme auslöst:

"Fenster kann nicht hinzugefügt werden - Token null ist nicht für eine Anwendung"

per Referenzen: 1 , 2 , , etc.

Sollte dies wirklich als "Bug" betrachtet werden, da wir offiziell angewiesen sind, Activity.getApplication() zu verwenden, und es dennoch nicht wie angekündigt funktioniert?

Jim

642
gymshoe

Verwenden Sie statt getApplicationContext() nur ActivityName.this.

1305
Steven L

Die Verwendung von this hat bei mir nicht funktioniert, aber MyActivityName.this. Hoffe, dies hilft jedem, der this nicht zum Arbeiten bringen konnte.

184
TrueCoke

Sie können getApplicationContext() weiterhin verwenden, aber vor der Verwendung sollten Sie dieses Flag hinzufügen: dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT), und der Fehler wird nicht angezeigt.

Fügen Sie Ihrem Manifest die folgende Berechtigung hinzu:

<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />
56
codezjx

Sie haben das Problem korrekt erkannt, als Sie sagten "... für AlertDialog () ist weder getApplicationContext () noch getApplication () als Kontext zulässig, da die folgende Ausnahme ausgelöst wird: 'Fenster-Token-Null kann nicht hinzugefügt werden eine Bewerbung'"

Zum Erstellen eines Dialogfelds benötigen Sie einen Aktivitätskontext ​​oder einen Dienstkontext, nicht einen Anwendungskontext ​​(sowohl getApplicationContext () als auch getApplication ()) Anwendungskontext).

So erhalten Sie den Aktivitätskontext:

(1) In einer Aktivität oder Dienstleistung:

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

(2) In einem Fragment: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

Speicherlecks sind kein Problem, das der "this" -Referenz eigen ist, bei der es sich um eine Objektreferenz auf sich selbst handelt (d. H. Um die Referenz auf den tatsächlich zugewiesenen Speicher zum Speichern der Objektdaten). Es passiert mit jedem zugewiesenen Speicher, für den der Garbage Collector (GC) nicht mehr freigeben kann, nachdem der zugewiesene Speicher seine Nutzungsdauer überschritten hat.

Die meiste Zeit, wenn eine Variable den Gültigkeitsbereich verlässt, wird der Speicher vom GC zurückgefordert. Es können jedoch Speicherverluste auftreten, wenn der Verweis auf ein Objekt, das von einer Variablen, z. B. "x", gespeichert wird, auch nachdem das Objekt seine Nutzungsdauer überschritten hat. Der zugewiesene Speicher geht daher verloren, solange "x" einen Verweis darauf enthält, da GC den Speicher nicht freigibt , solange auf diesen Speicher noch verwiesen wird. Manchmal treten Speicherverluste nicht auf, weil eine Kette von Referenzen auf den zugewiesenen Speicher verweist. In diesem Fall gibt der GC den Speicher erst frei, wenn alle Verweise auf diesen Speicher entfernt wurden.

Um Speicherverluste zu vermeiden, überprüfen Sie Ihren Code auf logische Fehler, die dazu führen, dass der zugewiesene Speicher durch "this" (oder andere Verweise) auf unbestimmte Zeit referenziert wird. Denken Sie daran, auch nach Kettenreferenzen zu suchen. Mit den folgenden Tools können Sie die Speichernutzung analysieren und lästige Speicherlecks finden:

34
ONE

Ihr Dialog sollte kein "langlebiges Objekt, das einen Kontext benötigt" sein. Die Dokumentation ist verwirrend. Grundsätzlich, wenn Sie etwas tun wie:

static Dialog sDialog;

(beachte das statisch)

Dann in einer Aktivität, die Sie irgendwo gemacht haben

 sDialog = new Dialog(this);

Wahrscheinlich leckt die ursprüngliche Aktivität während einer Rotation oder Ähnlichem, wodurch die Aktivität zerstört wird. (Es sei denn, Sie bereinigen in onDestroy, aber in diesem Fall würden Sie das Dialog-Objekt wahrscheinlich nicht statisch machen.)

Für einige Datenstrukturen ist es sinnvoll, sie statisch und abhängig vom Anwendungskontext zu gestalten, im Allgemeinen jedoch nicht für UI-bezogene Dinge wie Dialoge. So etwas in der Art:

Dialog mDialog;

...

mDialog = new Dialog(this);

Ist in Ordnung und sollte die Aktivität nicht auslaufen lassen, da mDialog mit der Aktivität freigegeben würde, da sie nicht statisch ist.

34
Kevin TeslaCoil

Ich musste meinen Kontext über einen Konstruktor auf einem benutzerdefinierten Adapter senden, der in einem Fragment angezeigt wurde, und hatte dieses Problem mit getApplicationContext (). Ich habe es gelöst mit:

this.getActivity().getWindow().getContext() im Rückruf der Fragmente onCreate.

23
Grux

in Aktivität benutze einfach:

MyActivity.this

in Fragment:

getActivity();
22
Mahmoud Ayman

Klicken Sie in Activity auf die Schaltfläche, um ein Dialogfeld anzuzeigen

Dialog dialog = new Dialog(MyActivity.this);

Hat für mich gearbeitet.

19
P_Pran

Kleiner Hack: Sie können verhindern, dass Ihre Aktivität durch GC zerstört wird (Sie sollten es nicht tun, aber es kann in einigen Situationen hilfreich sein. Vergessen Sie nicht, contextForDialog auf null zu setzen, wenn es nicht mehr benötigt wird):

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();
    }
    ...
}
18
Mikalai Daronin

***** kotlin version *****

Sie sollten [email protected] anstelle von applicationContext oder baseContext übergeben.

14
MilaDroid

Wenn Sie ein Fragment verwenden und eine AlertDialog/Toast-Nachricht verwenden, verwenden Sie getActivity () im Kontextparameter.

so was

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

Ich habe ProgressDialog in einem Fragment verwendet und diesen Fehler beim Übergeben von getActivity().getApplicationContext() als Konstruktorparameter erhalten. Das Ändern auf getActivity().getBaseContext() hat auch nicht funktioniert.

Die Lösung, die für mich funktionierte, war, getActivity() zu bestehen; d.h.

progressDialog = new ProgressDialog(getActivity());

9
T.M

hinzufügen

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

und

"Android.permission.SYSTEM_ALERT_WINDOW"/> im Manifest

Es funktioniert jetzt für mich. Nachdem ich sogar die Anwendung geschlossen und geöffnet habe, gab es mir damals den Fehler.

9
AlphaStack

Wenn Sie sich außerhalb der Aktivität befinden, müssen Sie in Ihrer Funktion "NameOfMyActivity.this" als Aktivitätsaktivität Folgendes verwenden:

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

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

6
MSA

Versuchen Sie, den Kontext einer Aktivität zu verwenden, die sich unter dem Dialogfeld befindet. Aber seien Sie vorsichtig, wenn Sie "dieses" Schlüsselwort verwenden, da es nicht immer funktioniert.

Wenn Sie beispielsweise TabActivity als Host mit zwei Registerkarten haben und jede Registerkarte eine andere Aktivität ist und Sie versuchen, einen Dialog aus einer der Registerkarten (Aktivitäten) zu erstellen, und wenn Sie "this" verwenden, erhalten Sie die Ausnahme "In this" Der Falldialog sollte mit der Hostaktivität verbunden sein, die alles hostet und sichtbar macht. (Sie können sagen, dass der Kontext der übergeordneten Aktivität am sichtbarsten ist.)

Ich habe diese Informationen in keinem Dokument gefunden, sondern nur ausprobiert. Dies ist meine Lösung ohne starken Hintergrund. Wenn jemand mit besserem Wissen, zögern Sie nicht zu kommentieren.

5
Engin OZTURK

Wenn Sie ein Fragment verwenden und eine AlertDialog / Toast -Nachricht verwenden, verwenden Sie getActivity() im Kontextparameter.

Hat für mich gearbeitet.

Prost!

5
curlyreggie

Für zukünftige Leser sollte dies helfen:

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

Ich denke, es kann auch passieren, wenn Sie versuchen, einen Dialog aus einem Thread anzuzeigen, der nicht der Haupt-UI-Thread ist.

Verwenden Sie in diesem Fall runOnUiThread().

2
Erwan

Versuchen Sie getParent() an der kontextbezogenen Stelle wie neu AlertDialog.Builder(getParent()); Ich hoffe, es wird funktionieren, es hat bei mir funktioniert.

2
Priyank Joshi

Eine andere Möglichkeit besteht darin, einen Dialog wie folgt zu erstellen:

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

In meiner Fallarbeit:

this.getContext();
2
theWalker

Nachdem Sie sich die API angesehen haben, können Sie dem Dialogfeld Ihre Aktivität oder getActivity übergeben, wenn Sie sich in einem Fragment befinden. Bereinigen Sie es dann mit dialog.dismiss () in den Rückgabemethoden, um Lecks zu vermeiden.

Obwohl es nirgendwo explizit angegeben ist, scheint es, als ob Sie den Dialog in den OnClickHandlern zurückgegeben bekommen, nur um dies zu tun.

1
G_V

So habe ich denselben Fehler für meine Anwendung behoben:
Hinzufügen der folgenden Zeile nach dem Erstellen des Dialogfelds:

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

Sie müssen keinen Kontext erwerben. Dies ist besonders nützlich, wenn Sie einen anderen Dialog über dem aktuellen Dialog öffnen. Oder wenn es nicht bequem ist, einen Kontext zu bekommen.

Ich hoffe, dies kann Ihnen bei Ihrer App-Entwicklung helfen.

David

0
us_david

Wenn Ihr Dialog auf dem Adapter erstellt:

Übergeben Sie die Aktivität an den Adapterkonstruktor:

adapter = new MyAdapter(getActivity(),data);

Empfangen Sie auf dem Adapter:

 public MyAdapter(Activity activity, List<Data> dataList){
       this.activity = activity;
    }

Jetzt können Sie auf Ihrem Builder verwenden

            AlertDialog.Builder alert = new AlertDialog.Builder(activity);
0
josedlujan