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 möglicherweise Speicherlecks auftreten, wenn Aktivität zerstört und neu erstellt wird, selbst während einer einfachen Bildschirmdrehung. Aus einem verwandten Beitrag im Blog des Android-Entwicklers :
Es gibt zwei einfache Möglichkeiten, um kontextbezogene Speicherverluste zu vermeiden. Am naheliegendsten ist es, zu vermeiden, dass der Kontext außerhalb seines eigenen Bereichs entkommt. Das obige Beispiel zeigte 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 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, merken Sie sich das Anwendungsobjekt. Sie können es einfach erhalten, indem Sie Context.getApplicationContext () oder Activity.getApplication () aufrufen.
Aber für das AlertDialog()
weder getApplicationContext()
oder getApplication()
als Kontext akzeptabel, da es die Ausnahme auslöst:
"Fenster kann nicht hinzugefügt werden - Token null ist nicht für eine Anwendung geeignet"
gemäß Referenzen: 1 , 2 , 3 usw.
Sollte dies wirklich als "Fehler" angesehen werden, da uns offiziell empfohlen wird, ihn zu verwenden, Activity.getApplication()
und er dennoch nicht wie angekündigt funktioniert?
Jim
quelle
Antworten:
getApplicationContext()
Verwenden Sie stattdessen einfachActivityName.this
.quelle
Listener
Unterricht oft anonym-inner ist, machefinal Context ctx = this;
ich das einfach und bin weg;)Die Verwendung
this
hat bei mir nicht funktioniert, aberMyActivityName.this
funktioniert. Hoffe das hilft jedem, der nichtthis
zur Arbeit kommen konnte.quelle
this
innerhalb einer inneren Klasse arbeiten. Wenn Sie auf die Instanz einer äußeren Klasse verweisen möchten, müssen Sie dies wie bei angebenOuterClass.this
. Nur mitthis
immer auf die Instanz der innersten Klasse verweisen.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 Ihrem Manifest die folgende Berechtigung hinzu:
quelle
Sie haben das Problem korrekt identifiziert, als Sie sagten: "... für AlertDialog () ist weder getApplicationContext () noch getApplication () als Kontext akzeptabel, da die Ausnahme ausgelöst wird: 'Fenster kann nicht hinzugefügt werden - Token-Null ist nicht für eine Bewerbung'"
So erstellen Sie einen Dialog, benötigen Sie eine Aktivität Kontext oder einen Dienst - Kontext , kein Anwendungskontext (beide getApplicationContext () und GetApplication () geben einen Anwendungskontext).
So erhalten Sie den Aktivitätskontext :
(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 der "this" -Referenz innewohnt, die die Referenz eines Objekts auf sich selbst ist (dh die Referenz auf den tatsächlich zugewiesenen Speicher zum Speichern der Objektdaten). Dies geschieht mit jedem zugewiesenen Speicher, für den der Garbage Collector (GC) nicht freigeben kann, nachdem der zugewiesene Speicher seine Nutzungsdauer überschritten hat.
Wenn eine Variable den Gültigkeitsbereich verlässt, wird der Speicher meistens vom GC zurückgefordert. Speicherverluste können jedoch auftreten, wenn der Verweis auf ein Objekt, das von einer Variablen, z. B. "x", gehalten wird, auch dann bestehen bleibt, wenn 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 sind Speicherlecks aufgrund einer Kette von Verweisen auf den zugewiesenen Speicher nicht erkennbar . In einem solchen Fall gibt der GC den Speicher erst 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 der zugewiesene Speicher durch "this" (oder andere Referenzen) auf unbestimmte Zeit referenziert wird. Denken Sie auch daran, nach Kettenreferenzen zu suchen. Hier sind einige Tools, mit denen Sie die Speichernutzung analysieren und diese lästigen Speicherlecks finden können:
JRockit Missionskontrolle
JProbe
YourKit
AD4J
quelle
Ihr Dialog sollte kein "langlebiges Objekt sein, das einen Kontext benötigt". Die Dokumentation ist verwirrend. Grundsätzlich, wenn Sie etwas tun wie:
(Beachten Sie die statische )
Dann in einer Aktivität irgendwo, die Sie getan haben
Sie würden wahrscheinlich die ursprüngliche Aktivität während einer Rotation oder ähnlichem verlieren, was die Aktivität zerstören würde. (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 wäre es sinnvoll, sie statisch zu machen und auf dem Kontext der Anwendung zu basieren, im Allgemeinen jedoch nicht für UI-bezogene Dinge wie Dialoge. Also so etwas wie das:
Ist in Ordnung und sollte die Aktivität nicht verlieren, da mDialog mit der Aktivität freigegeben würde, da sie nicht statisch ist.
quelle
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()
imonCreate
Rückruf der Fragmente .quelle
Verwenden Sie in Aktivität einfach:
im Fragment:
quelle
In
Activity
auf Klicken der Schaltfläche , um ein Dialogfeld zeigtHat für mich gearbeitet.
quelle
***** Kotlin-Version *****
Sie sollten
this@YourActivity
anstelle vonapplicationContext
oder bestehenbaseContext
quelle
Kleiner Hack: Sie können verhindern, dass Ihre Aktivität durch GC zerstört wird (Sie sollten dies nicht tun, aber es kann in einigen Situationen hilfreich sein. Vergessen Sie nicht, die Einstellung festzulegen
contextForDialog
,null
wenn sie nicht mehr benötigt wird):quelle
Wenn Sie ein Fragment verwenden und die AlertDialog / Toast-Nachricht verwenden, verwenden Sie getActivity () im Kontextparameter.
so was
quelle
Verwenden Sie einfach Folgendes:
FÜR JAVA-BENUTZER
Falls Sie Aktivität verwenden ->
AlertDialog.Builder builder = new AlertDialog.Builder(this);
ODER
AlertDialog.Builder builder = new AlertDialog.Builder(your_activity.this);
Falls Sie Fragment verwenden ->
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
FÜR KOTLIN-BENUTZER
Falls Sie Aktivität verwenden ->
val builder = AlertDialog.Builder(this)
ODER
val builder = AlertDialog.Builder(this@your_activity.this)
Falls Sie Fragment verwenden ->
val builder = AlertDialog.Builder(activity!!)
quelle
Hinzufügen
und
"android.permission.SYSTEM_ALERT_WINDOW"/>
im ManifestEs funktioniert jetzt für mich. Nachdem ich die Anwendung sogar geschlossen und geöffnet hatte, gab mir der Fehler zu diesem Zeitpunkt.
quelle
Ich habe
ProgressDialog
in einem Fragment verwendet und diesen Fehler beim ÜbergebengetActivity().getApplicationContext()
als Konstruktorparameter erhalten. Ändern ingetActivity().getBaseContext()
hat auch nicht funktioniert.Die Lösung, die für mich funktionierte, war zu bestehen
getActivity()
; dhprogressDialog = new ProgressDialog(getActivity());
quelle
Verwenden
MyDialog md = new MyDialog(MyActivity.this.getParent());
quelle
Wenn Sie sich außerhalb der Aktivität befinden, müssen Sie in Ihrer Funktion "NameOfMyActivity.this" als Aktivitätsaktivität verwenden. Beispiel:
quelle
Wenn Sie ein Fragment und eine
AlertDialog / Toast
Nachricht verwenden, verwenden SiegetActivity()
den Kontextparameter.Hat für mich gearbeitet.
Prost!
quelle
Versuchen Sie, den Kontext einer Aktivität zu verwenden, die sich unter dem Dialog befindet. Seien Sie jedoch vorsichtig, wenn Sie das Schlüsselwort "this" verwenden, da es nicht jedes Mal funktioniert.
Wenn Sie beispielsweise TabActivity als Host mit zwei Registerkarten haben und jede Registerkarte eine andere Aktivität ist und wenn Sie versuchen, einen Dialog aus einer der Registerkarten (Aktivitäten) zu erstellen, und wenn Sie "dies" verwenden, erhalten Sie eine Ausnahme Der Falldialog sollte mit der Hostaktivität verbunden sein, die alles hostet und sichtbar ist. (Sie können den Kontext der sichtbarsten übergeordneten Aktivität sagen)
Ich habe diese Informationen in keinem Dokument gefunden, sondern nur durch einen Versuch. Dies ist meine Lösung ohne starken Hintergrund. Wenn jemand mit besserem Wissen, zögern Sie nicht zu kommentieren.
quelle
Für zukünftige Leser sollte dies helfen:
quelle
In meiner Fallarbeit:
quelle
Oder Sie können den Dialog wie folgt erstellen:
quelle
Ich denke, es kann auch passieren, wenn Sie versuchen, einen Dialog aus einem Thread anzuzeigen, der nicht der Haupt-UI-Thread ist.
Verwenden
runOnUiThread()
Sie in diesem Fall.quelle
Versuchen Sie es
getParent()
am Argumentationsort des Kontextes wie neu.AlertDialog.Builder(getParent());
Hoffe, es wird funktionieren, es hat bei mir funktioniert.quelle
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, und es dann mit dialog.dismiss () in den Rückgabemethoden zwangsweise bereinigen, um Lecks zu vermeiden.
Obwohl es nirgendwo explizit angegeben ist, wo ich weiß, scheint es, dass Sie den Dialog in den OnClickHandlers zurückgegeben haben, nur um dies zu tun.
quelle
Wenn Ihr Dialog auf dem Adapter erstellt wird:
Übergeben Sie die Aktivität an den Adapterkonstruktor:
Auf dem Adapter empfangen:
Jetzt können Sie auf Ihrem Builder verwenden
quelle
So habe ich denselben Fehler für meine Anwendung behoben:
Hinzufügen der folgenden Zeile nach dem Erstellen des Dialogfelds:
Sie müssen keinen Kontext erwerben. Dies ist besonders nützlich, wenn Sie ein anderes Dialogfeld über dem aktuell angezeigten Dialogfeld öffnen. Oder wenn es nicht bequem ist, einen Kontext zu erhalten.
Ich hoffe, dies kann Ihnen bei Ihrer App-Entwicklung helfen.
David
quelle
quelle