Ich habe dieses Problem seit Monaten untersucht und verschiedene Lösungen gefunden, mit denen ich nicht zufrieden bin, da es sich um massive Hacks handelt. Ich kann immer noch nicht glauben, dass eine Klasse, die im Design fehlerhaft war, es in das Framework geschafft hat und niemand darüber spricht, also muss mir wohl etwas fehlen.
Das Problem ist mit AsyncTask
. Laut Dokumentation ist es
"Ermöglicht das Ausführen von Hintergrundoperationen und das Veröffentlichen von Ergebnissen auf dem UI-Thread, ohne dass Threads und / oder Handler bearbeitet werden müssen."
Das Beispiel zeigt dann weiterhin, wie eine beispielhafte showDialog()
Methode aufgerufen wird onPostExecute()
. Dies scheint mir jedoch völlig erfunden zu sein, da das Context
Anzeigen eines Dialogfelds immer einen Verweis auf ein gültiges Objekt erfordert und eine AsyncTask niemals einen starken Verweis auf ein Kontextobjekt enthalten darf .
Der Grund liegt auf der Hand: Was passiert, wenn die Aktivität zerstört wird, die die Aufgabe ausgelöst hat? Dies kann die ganze Zeit passieren, z. B. weil Sie den Bildschirm umgedreht haben. Wenn die Aufgabe einen Verweis auf den Kontext enthält, der sie erstellt hat, halten Sie nicht nur an einem nutzlosen Kontextobjekt fest (das Fenster wurde zerstört und jede UI-Interaktion schlägt mit einer Ausnahme fehl!), Sondern Sie riskieren sogar das Erstellen eines Speicherleck.
Sofern meine Logik hier nicht fehlerhaft ist, bedeutet dies: onPostExecute()
ist völlig nutzlos, denn was nützt es, wenn diese Methode auf dem UI-Thread ausgeführt wird, wenn Sie keinen Zugriff auf einen Kontext haben? Sie können hier nichts Sinnvolles tun.
Eine Problemumgehung besteht darin, keine Kontextinstanzen an eine AsyncTask zu übergeben, sondern eine Handler
Instanz. Das funktioniert: Da ein Handler den Kontext und die Aufgabe lose bindet, können Sie Nachrichten zwischen ihnen austauschen, ohne ein Leck zu riskieren (richtig?). Dies würde jedoch bedeuten, dass die Prämisse von AsyncTask, dass Sie sich nicht um Handler kümmern müssen, falsch ist. Es scheint auch so, als würde man Handler missbrauchen, da Sie Nachrichten im selben Thread senden und empfangen (Sie erstellen sie im UI-Thread und senden sie in onPostExecute () durch, das auch im UI-Thread ausgeführt wird).
Um das Ganze abzurunden, haben Sie trotz dieser Problemumgehung immer noch das Problem, dass Sie bei Zerstörung des Kontexts keine Aufzeichnungen über die von ihm ausgelösten Aufgaben haben. Das bedeutet, dass Sie alle Aufgaben neu starten müssen, wenn Sie den Kontext neu erstellen, z. B. nach einer Änderung der Bildschirmausrichtung. Das ist langsam und verschwenderisch.
Meine Lösung hierfür (wie in der Droid-Fu-Bibliothek implementiert ) besteht darin, eine Zuordnung von WeakReference
s von Komponentennamen zu ihren aktuellen Instanzen auf dem eindeutigen Anwendungsobjekt beizubehalten . Jedes Mal, wenn eine AsyncTask gestartet wird, zeichnet sie den aufrufenden Kontext in dieser Zuordnung auf und ruft bei jedem Rückruf die aktuelle Kontextinstanz aus dieser Zuordnung ab. Dies stellt sicher, dass Sie niemals auf eine veraltete Kontextinstanz verweisen und in den Rückrufen immer Zugriff auf einen gültigen Kontext haben, damit Sie dort sinnvolle UI-Arbeiten ausführen können. Es leckt auch nicht, da die Referenzen schwach sind und gelöscht werden, wenn keine Instanz einer bestimmten Komponente mehr vorhanden ist.
Trotzdem ist es eine komplexe Problemumgehung und erfordert die Unterklasse einiger Droid-Fu-Bibliotheksklassen, was dies zu einem ziemlich aufdringlichen Ansatz macht.
Jetzt möchte ich einfach nur wissen: Vermisse ich nur massiv etwas oder ist AsyncTask wirklich völlig fehlerhaft? Wie arbeiten Ihre Erfahrungen damit? Wie haben Sie dieses Problem gelöst?
Danke für deinen Beitrag.