Zitiert in der Dokumentation zu AsyncTask gefunden hier , heißt es:
AsyncTasks sollten idealerweise für kurze Vorgänge (höchstens einige Sekunden) verwendet werden. Wenn Sie Threads über einen längeren Zeitraum laufen lassen müssen, wird dringend empfohlen, die verschiedenen APIs zu verwenden, die vom Paket java.util.concurrent bereitgestellt werden, z Executor, ThreadPoolExecutor und FutureTask.
Nun stellt sich meine Frage: Warum? Die doInBackground()
Funktion wird vom UI-Thread ausgeführt. Welchen Schaden kann es also haben, wenn hier eine lange Operation ausgeführt wird?
android
android-asynctask
user1730789
quelle
quelle
doInBackground
den Bildschirm einfriert, wenn kein Fortschrittsbalken verwendet wird.Antworten:
Es ist eine sehr gute Frage, es braucht Zeit als Android-Programmierer, um das Problem vollständig zu verstehen. In der Tat haben AsyncTask zwei Hauptprobleme, die miteinander zusammenhängen:
In der RoboSpice Motivations-App ( verfügbar bei Google Play ) beantworten wir diese Frage ausführlich. Es bietet einen detaillierten Überblick über AsyncTasks, Loader, deren Funktionen und Nachteile und stellt Ihnen eine alternative Lösung für Netzwerkanforderungen vor: RoboSpice. Netzwerkanforderungen sind eine häufige Anforderung in Android und werden von Natur aus lange ausgeführt. Hier ist ein Auszug aus der App:
Der Lebenszyklus von AsyncTask und Aktivität
AsyncTasks folgen nicht dem Lebenszyklus von Aktivitätsinstanzen. Wenn Sie eine AsyncTask innerhalb einer Aktivität starten und das Gerät drehen, wird die Aktivität zerstört und eine neue Instanz erstellt. Aber die AsyncTask wird nicht sterben. Es wird weiterleben, bis es fertig ist.
Wenn dies abgeschlossen ist, aktualisiert die AsyncTask die Benutzeroberfläche der neuen Aktivität nicht. In der Tat wird die frühere Instanz der Aktivität aktualisiert, die nicht mehr angezeigt wird. Dies kann zu einer Ausnahme vom Typ java.lang.IllegalArgumentException führen: Ansicht, die nicht an den Fenstermanager angehängt ist, wenn Sie beispielsweise findViewById verwenden, um eine Ansicht innerhalb der Aktivität abzurufen.
Speicherverlust Problem
Es ist sehr praktisch, AsyncTasks als innere Klassen Ihrer Aktivitäten zu erstellen. Da die AsyncTask die Ansichten der Aktivität bearbeiten muss, wenn die Aufgabe abgeschlossen ist oder ausgeführt wird, erscheint die Verwendung einer inneren Klasse der Aktivität praktisch: Innere Klassen können direkt auf jedes Feld der äußeren Klasse zugreifen.
Dies bedeutet jedoch, dass die innere Klasse einen unsichtbaren Verweis auf ihre äußere Klasseninstanz enthält: die Aktivität.
Auf lange Sicht führt dies zu einem Speicherverlust: Wenn die AsyncTask lange anhält, bleibt die Aktivität "am Leben", während Android sie gerne entfernen möchte, da sie nicht mehr angezeigt werden kann. Die Aktivität kann nicht durch Müll gesammelt werden. Dies ist ein zentraler Mechanismus für Android, um Ressourcen auf dem Gerät zu schonen.
Es ist wirklich eine sehr, sehr schlechte Idee, AsyncTasks für lange laufende Vorgänge zu verwenden. Trotzdem eignen sie sich gut für kurzlebige Personen wie das Aktualisieren einer Ansicht nach 1 oder 2 Sekunden.
Ich ermutige Sie, die herunterzuladen empfehle RoboSpice Motivations-App Sie erklärt dies ausführlich und bietet Beispiele und Demonstrationen der verschiedenen Möglichkeiten, einige Hintergrundoperationen durchzuführen.
quelle
Weil
AsyncTask
standardmäßig ein Thread-Pool verwendet wird , den Sie nicht erstellt haben . Binden Sie niemals Ressourcen aus einem Pool, den Sie nicht erstellt haben, da Sie die Anforderungen dieses Pools nicht kennen. Binden Sie niemals Ressourcen aus einem Pool, den Sie nicht erstellt haben, wenn die Dokumentation für diesen Pool Sie dazu auffordert, dies nicht zu tun, wie dies hier der Fall ist.Insbesondere ab Android 3.2 enthält der
AsyncTask
standardmäßig verwendete Thread-Pool (für Apps mit einerandroid:targetSdkVersion
Einstellung von 13 oder höher) nur einen Thread. Wenn Sie diesen Thread auf unbestimmte Zeit binden, wird keine Ihrer anderen Aufgaben ausgeführt.quelle
Service
Verwenden Sie für a einfach aThread
oder aThreadPoolExecutor
.TimerTask
ist von Standard Java, nicht Android.TimerTask
wurde weitgehend zugunsten von aufgegebenScheduledExecutorService
(das trotz seines Namens Teil von Standard-Java ist). Beide sind nicht an Android gebunden, sodass Sie immer noch einen Dienst benötigen, wenn Sie erwarten, dass diese Dinge im Hintergrund ausgeführt werden. Und Sie sollten wirklich in Betracht ziehenAlarmManager
, von Android aus, damit Sie keinen Dienst benötigen, der nur die Uhr tickt.Aysnc-Aufgaben sind spezialisierte Threads, die weiterhin für die Benutzeroberfläche Ihrer Apps verwendet werden sollen, aber gleichzeitig die ressourcenintensiven Aufgaben des UI-Threads beibehalten. Wenn Sie beispielsweise beim Aktualisieren von Listen, Ändern Ihrer Ansichten usw. einige Abruf- oder Aktualisierungsvorgänge ausführen müssen, sollten Sie asynchrone Aufgaben verwenden, damit Sie diese Vorgänge vom UI-Thread fernhalten können. Beachten Sie jedoch, dass diese Vorgänge weiterhin irgendwie mit der UI verbunden sind .
Für länger laufende Aufgaben, für die keine Aktualisierung der Benutzeroberfläche erforderlich ist, können Sie stattdessen Dienste verwenden, da diese auch ohne Benutzeroberfläche ausgeführt werden können.
Verwenden Sie für kurze Aufgaben asynchrone Aufgaben, da diese vom Betriebssystem beendet werden können, nachdem Ihre Laichaktivität beendet ist (normalerweise stirbt sie nicht während des Betriebs, sondern erledigt ihre Aufgabe). Verwenden Sie stattdessen Dienste für lange und sich wiederholende Aufgaben.
Weitere Informationen finden Sie unter Themen:
AsyncTask länger als ein paar Sekunden?
und
AsyncTask wird auch dann nicht gestoppt, wenn die Aktivität zerstört wurde
quelle
Das Problem mit AsyncTask besteht darin, dass, wenn es als nicht statische innere Klasse der Aktivität definiert ist, ein Verweis auf die Aktivität vorhanden ist. In dem Szenario, in dem die Aktivität des Containers der asynchronen Aufgabe beendet wird, die Hintergrundarbeit in AsyncTask jedoch fortgesetzt wird, wird das Aktivitätsobjekt nicht durch Müll gesammelt, da ein Verweis darauf vorhanden ist. Dies führt zu einem Speicherverlust.
Die Lösung, um dies zu beheben, besteht darin, eine asynchrone Aufgabe als statische innere Aktivitätsklasse zu definieren und einen schwachen Verweis auf den Kontext zu verwenden.
Trotzdem ist es eine gute Idee, es für einfache und schnelle Hintergrundaufgaben zu verwenden. Um eine App mit sauberem Code zu entwickeln, ist es besser, RxJava zu verwenden, um komplexe Hintergrundaufgaben auszuführen und die Benutzeroberfläche mit den daraus resultierenden Ergebnissen zu aktualisieren.
quelle