696 Stimmen

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

Meine Aktivität versucht, einen AlertDialog zu erstellen, der einen Kontext als Parameter erfordert. Dies funktioniert wie erwartet, wenn ich verwenden:

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

Allerdings bin ich misstrauisch bei der Verwendung von "this" als Kontext aufgrund des Potenzials für Speicherlecks, wenn Aktivität zerstört und neu erstellt wird, auch während etwas Einfaches wie eine Bildschirmdrehung. Von einer zugehöriger Beitrag im Blog der Android-Entwickler :

Es gibt zwei einfache Möglichkeiten, um kontextbezogene Speicherlecks zu vermeiden. Die offensichtlichste besteht darin, den Kontext nicht außerhalb seines eigenen Bereichs zu lassen. Das obige Beispiel zeigt den Fall einer statischen Referenz, aber innere Klassen und ihre implizite Referenz auf die äußere Klasse können ebenso gefährlich sein. Die zweite Lösung besteht darin, den Anwendungskontext zu verwenden. Dieser Kontext lebt so lange, wie Ihre Anwendung existiert und ist nicht vom Lebenszyklus der Aktivitäten abhängig. Wenn Sie planen, langlebige Objekte zu behalten, die einen Kontext benötigen, sollten Sie sich das Anwendungsobjekt merken. Sie können es leicht erhalten, indem Sie Context.getApplicationContext() oder Activity.getApplication() aufrufen.

Aber für die AlertDialog() weder getApplicationContext() o getApplication() ist als Context akzeptabel, da er die Ausnahme auslöst:

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

nach Referenzen: 1 , 2 , 3 , usw.

Sollte dies also wirklich als "Fehler" betrachtet werden, da uns offiziell empfohlen wird, die Activity.getApplication() und trotzdem funktioniert es nicht wie versprochen?

Jim

1406voto

Steven L Punkte 15144

Anstelle von getApplicationContext() verwenden Sie einfach ActivityName.this .

201voto

TrueCoke Punkte 2396

Verwendung von this hat bei mir nicht funktioniert, aber MyActivityName.this hat. Ich hoffe, dies hilft allen, die nicht in der Lage waren this zur Arbeit.

64voto

codezjx Punkte 8832

Sie können weiterhin verwenden getApplicationContext() 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 die folgende Erlaubnis zu Ihrem Manifest hinzu:

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

42voto

ONE Punkte 563

Sie haben das Problem richtig erkannt, als Sie sagten: "... für AlertDialog() ist weder getApplicationContext() noch getApplication() als Kontext akzeptabel, da es die Ausnahme auslöst: 'Unable to add window - token null is not for an application'".

Um einen Dialog zu erstellen, benötigen Sie eine Kontext der Aktivität oder eine Dienstkontext , nicht ein Anwendungskontext (sowohl getApplicationContext() als auch getApplication() geben einen Anwendungskontext zurück).

So bekommen Sie die Kontext der Aktivität :

(1) In einer Aktivität oder einem Dienst:

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

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

Speicherlecks sind kein Problem, das dem "this"-Verweis innewohnt, der der Verweis eines Objekts auf sich selbst ist (d. h. der Verweis auf den tatsächlich zugewiesenen Speicher zum Speichern der Objektdaten). Es tritt auf cualquier zugewiesener Speicher, den der Garbage Collector (GC) nicht mehr freigeben kann, nachdem der zugewiesene Speicher seine Nutzungsdauer überschritten hat.

In den meisten Fällen, wenn eine Variable den Gültigkeitsbereich verlässt, wird der Speicher von der GC zurückgewonnen. Es kann jedoch zu Speicherverlusten kommen, wenn der Verweis auf ein Objekt, das von einer Variablen, z. B. "x", gehalten wird, auch dann noch besteht, wenn das Objekt seine nützliche Lebensdauer überschritten hat. Der zugewiesene Speicher geht also verloren, solange "x" einen Verweis darauf enthält, weil GC wird nicht den Speicher so lange freigeben, wie auf diesen Speicher noch verwiesen wird. Manchmal sind Speicherlecks nicht offensichtlich, weil die eine Kette von Referenzen auf den zugewiesenen Speicher. In einem solchen Fall gibt der GC den Speicher erst dann frei, wenn alle Verweise auf diesen Speicher entfernt wurden.

Um Speicherlecks zu vermeiden, überprüfen Sie Ihren Code auf logische Fehler, die dazu führen, dass zugewiesener Speicher auf unbestimmte Zeit von "this" (oder anderen Referenzen) referenziert wird. Vergessen Sie nicht, auch auf Kettenreferenzen zu achten. Hier finden Sie einige Tools, die Ihnen helfen können, die Speichernutzung zu analysieren und diese lästigen Speicherlecks zu finden:

34voto

Kevin TeslaCoil Punkte 9917

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

static Dialog sDialog;

(Beachten Sie die statisch )

Dann haben Sie bei einer Aktivität irgendwo

 sDialog = new Dialog(this);

Sie würden wahrscheinlich die ursprüngliche Aktivität während einer Rotation oder ähnlichem auslaufen lassen, was die Aktivität zerstören würde. (Es sei denn, Sie bereinigen in onDestroy, aber in diesem Fall würden Sie wahrscheinlich nicht machen das Dialog-Objekt statisch)

Für einige Datenstrukturen wäre es sinnvoll, sie statisch zu machen und vom Anwendungskontext abhängig zu machen, aber im Allgemeinen nicht für UI-bezogene Dinge, wie Dialoge. Also etwas wie dies:

Dialog mDialog;

...

mDialog = new Dialog(this);

Ist in Ordnung und sollte nicht die Aktivität als mDialog würde mit der Aktivität freigegeben werden, da es nicht statisch ist lecken.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X