In meinem Code wird eine Warnung angezeigt, die besagt:
Diese AsyncTask-Klasse sollte statisch sein, da sonst Lecks auftreten können (anonym android.os.AsyncTask)
Die vollständige Warnung lautet:
Diese AsyncTask-Klasse sollte statisch sein, da sonst Lecks auftreten können (anonym android.os.AsyncTask). Ein statisches Feld leckt Kontexte. Nicht statische innere Klassen haben einen impliziten Verweis auf ihre äußere Klasse. Wenn diese äußere Klasse beispielsweise ein Fragment oder eine Aktivität ist, bedeutet diese Referenz, dass der lang laufende Handler / Loader / Task einen Verweis auf die Aktivität enthält, der verhindert, dass Müll gesammelt wird. In ähnlicher Weise können direkte Feldverweise auf Aktivitäten und Fragmente dieser länger laufenden Instanzen zu Lecks führen. ViewModel-Klassen sollten niemals auf Ansichten oder Nichtanwendungskontexte verweisen.
Das ist mein Code:
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
Wie korrigiere ich das?
quelle
myActivity.getApplication()
in den privaten Konstruktor für den Singleton, um RoomDB-Klassen und andere Klassen zu initialisieren). Meine ViewModels erhalten die Singleton-Instanz als private Referenz, um einige Operationen an der Datenbank auszuführen. Die ViewModels importieren also das Singleton-Paket sowieandroid.app.Application
eines davon sogarandroid.app.Activity
. Da "the Singleton" diese ViewModels nicht importieren muss, um zu funktionieren, können dennoch Speicherlecks auftreten?Antworten:
Nicht statische innere Klassen enthalten einen Verweis auf die enthaltende Klasse. Wenn Sie
AsyncTask
als innere Klasse deklarieren , lebt sie möglicherweise länger als die enthaltendeActivity
Klasse. Dies liegt an der impliziten Bezugnahme auf die enthaltende Klasse. Dies verhindert, dass die Aktivität durch Müll gesammelt wird, daher der Speicherverlust.Verwenden Sie zur Lösung Ihres Problems entweder eine statisch verschachtelte Klasse anstelle einer anonymen, lokalen und inneren Klasse oder eine Klasse der obersten Ebene.
quelle
Verwendung einer statischen inneren AsyncTask-Klasse
Um Undichtigkeiten zu vermeiden, können Sie die innere Klasse statisch machen. Das Problem dabei ist jedoch, dass Sie keinen Zugriff mehr auf die Benutzeroberflächenansichten oder Mitgliedsvariablen der Aktivität haben. Sie können einen Verweis auf das übergeben,
Context
aber dann besteht das gleiche Risiko eines Speicherverlusts. (Android kann die Aktivität nach dem Schließen nicht mit Müll sammeln, wenn die AsyncTask-Klasse einen starken Verweis darauf hat.) Die Lösung besteht darin, einen schwachen Verweis auf die Aktivität (oder was auch immerContext
Sie benötigen) zu erstellen .Anmerkungen
AsyncTask
Tutorials da draußen beschäftigen sich immer noch nicht damit (siehe hier , hier , hier und hier ).AsyncTask
eine erstklassige Klasse wären . Eine statische innere Klasse ist im Grunde dieselbe wie eine Klasse der obersten Ebene in Java.Wenn Sie die Aktivität selbst nicht benötigen, aber dennoch den Kontext möchten (z. B. um a anzuzeigen
Toast
), können Sie einen Verweis auf den App-Kontext übergeben. In diesem Fall würde derAsyncTask
Konstruktor folgendermaßen aussehen:Kotlin
Geben Sie in Kotlin einfach nicht das
inner
Schlüsselwort für die innere Klasse an. Dies macht es standardmäßig statisch.quelle
onPostExecute
Methode wieder in dem obigen Code. Sie können sehen, dass ich dort die Benutzeroberfläche aktualisiert habeTextView
. Verwenden Sie einfachactivity.findViewById
, um einen Verweis auf das zu aktualisierende UI-Element zu erhalten.activity.isFinishing()
Scheck herausnehmen und möglicherweise durch einenfragment.isRemoving()
Scheck ersetzen . Ich habe in letzter Zeit jedoch nicht viel mit Fragmenten gearbeitet.AsyncTask
Konstruktor einen Verweis auf Ihre äußere Klasse. Und indoInBackground()
können Sie einen Verweis auf die äußere Klasse mit bekommenMyOuterClass ref = classReference.get()
. Überprüfen Sie aufnull
. (2) InonPostExecute()
aktualisieren Sie die Benutzeroberfläche nur mit den Ergebnissen der Hintergrundaufgabe. Es ist genau wie bei jedem anderen Mal, wenn Sie die Benutzeroberfläche aktualisieren. Die Überprüfungactivity.isFinishing()
besteht nur darin, sicherzustellen, dass die Aktivität noch nicht abgeschlossen ist. In diesem Fall wäre es sinnlos, die Benutzeroberfläche zu aktualisieren.Diese
AsyncTask
Klasse sollte statisch sein, da sonst Lecks auftreten könnenActivity
zerstört wird, laufenAsyncTask
(beidestatic
odernon-static
) nochnon-static
(AsyncTask
) ist, verweist sie auf die äußere Klasse (Activity
).Garbage Collected
wird es freigegeben. Wenn ein Objekt nicht verwendet wird undGarbage Collected
es nicht freigeben kann => Speicherverlust=> Wenn
AsyncTask
janon-static
,Activity
wird das Ereignis nicht freigegeben, es wird zerstört => LeckLösung für die Aktualisierung der Benutzeroberfläche, nachdem AsyncTask als statische Klasse ohne Leck erstellt wurde
1) Verwenden Sie
WeakReference
wie @ Suragch Antwort2) Senden und entfernen Sie
Activity
Verweise auf (von)AsyncTask
quelle
onDestroy()
wird nicht garantiert jedes Mal