AsyncTask
ist eine großartige Sache, um komplexe Aufgaben in einem anderen Thread auszuführen.
Wenn sich jedoch die Ausrichtung oder eine andere Konfiguration ändert, während das AsyncTask
noch ausgeführt wird, wird der Strom Activity
zerstört und neu gestartet. Wenn die Instanz von AsyncTask
mit dieser Aktivität verbunden ist, schlägt sie fehl und verursacht ein Meldungsfenster "Schließen erzwingen".
Daher suche ich nach einer Art "Best Practice", um diese Fehler zu vermeiden und zu verhindern, dass AsyncTask fehlschlägt.
Was ich bisher gesehen habe ist:
- Deaktivieren Sie Orientierungsänderungen. (Sicher nicht so, wie Sie damit umgehen sollten.)
- Lassen Sie die Aufgabe überleben und aktualisieren Sie sie mit der neuen Aktivitätsinstanz über
onRetainNonConfigurationInstance
- Brechen Sie die Aufgabe einfach ab, wenn die
Activity
zerstört ist, und starten Sie sie neu, wenn dieActivity
erneut erstellt wird. - Binden der Aufgabe an die Anwendungsklasse anstelle der Aktivitätsinstanz.
- Einige im Projekt "Regale" verwendete Methode (über onRestoreInstanceState)
Einige Codebeispiele:
Android AsyncTasks während einer Bildschirmrotation, Teil I und Teil II
Können Sie mir helfen, den besten Ansatz zu finden, der das Problem am besten löst und auch einfach zu implementieren ist? Der Code selbst ist ebenfalls wichtig, da ich nicht weiß, wie ich das richtig lösen soll.
quelle
Antworten:
Sie NICHT verwenden ,
android:configChanges
um dieses Problem zu beheben. Das ist eine sehr schlechte Praxis.Verwenden Sie auch NICHT
Activity#onRetainNonConfigurationInstance()
. Dies ist weniger modular und fürFragment
Anwendungen auf Basis nicht gut geeignet .Sie können meinen Artikel lesen, in dem beschrieben wird, wie Konfigurationsänderungen mit beibehaltenen
Fragment
s behandelt werden. Es löst das Problem,AsyncTask
eine Änderung über eine Rotation hinweg gut beizubehalten. Sie müssen im Grunde Ihre GastgeberAsyncTask
innerhalb einesFragment
, AnrufsetRetainInstance(true)
auf dasFragment
, und die BerichtAsyncTask
Fortschritte / Ergebnisse s‘wieder auf , es istActivity
durch die beibehaltenFragment
.quelle
TabActivity
. Um ehrlich zu sein, ich bin mir nicht sicher, warum wir überhaupt darüber sprechen ... alle sind sich einig, dass dies derFragment
richtige Weg ist. :)Normalerweise löse ich dieses Problem, indem meine AsyncTasks im .onPostExecute () -Rückruf Broadcast-Absichten auslösen, damit sie die Aktivität, mit der sie direkt gestartet wurden, nicht ändern. Die Aktivitäten hören diese Sendungen mit dynamischen BroadcastReceivern ab und handeln entsprechend.
Auf diese Weise müssen sich die AsyncTasks nicht um die spezifische Aktivitätsinstanz kümmern, die ihr Ergebnis verarbeitet. Sie "schreien" nur, wenn sie fertig sind, und wenn sich eine Aktivität in dieser Zeit befindet (aktiv und konzentriert / in ihrem wieder aufgenommenen Zustand), die an den Ergebnissen der Aufgabe interessiert ist, wird sie bearbeitet.
Dies ist mit etwas mehr Aufwand verbunden, da die Laufzeit die Übertragung übernehmen muss, aber es macht mir normalerweise nichts aus. Ich denke, die Verwendung des LocalBroadcastManager anstelle des standardmäßigen systemweiten Systems beschleunigt die Dinge ein wenig.
quelle
Hier ist ein weiteres Beispiel für eine AsyncTask, mit der a
Fragment
zur Änderung der Laufzeitkonfiguration (z. B. wenn der Benutzer den Bildschirm dreht) verwendet wirdsetRetainInstance(true)
. Ein bestimmter (regelmäßig aktualisierter) Fortschrittsbalken wird ebenfalls gezeigt.Das Beispiel basiert teilweise auf den offiziellen Dokumenten Beibehalten eines Objekts während einer Konfigurationsänderung .
In diesem Beispiel ist die Arbeit, die einen Hintergrund-Thread erfordert, das bloße Laden eines Bildes aus dem Internet in die Benutzeroberfläche.
Alex Lockwood scheint recht zu haben, dass es eine bewährte Methode ist, Änderungen der Laufzeitkonfiguration mit AsyncTasks mithilfe eines "beibehaltenen Fragments" zu verarbeiten.
onRetainNonConfigurationInstance()
wird in Lint in Android Studio veraltet. Die offiziellen Dokumente warnen uns davorandroid:configChanges
, von der Handhabung der Konfigurationsänderung selbst ...Dann gibt es die Frage, ob man überhaupt eine AsyncTask für den Hintergrund-Thread verwenden soll.
Die offizielle Referenz für AsyncTask warnt ...
Alternativ kann ein Dienst, ein Loader (mit einem CursorLoader oder AsyncTaskLoader) oder ein Inhaltsanbieter verwendet werden, um asynchrone Vorgänge auszuführen.
Ich teile den Rest des Beitrags in:
Der Ablauf
Beginnen Sie mit einer grundlegenden AsyncTask als innere Klasse einer Aktivität (es muss keine innere Klasse sein, aber es wird wahrscheinlich bequem sein). Zu diesem Zeitpunkt verarbeitet die AsyncTask keine Änderungen der Laufzeitkonfiguration.
Fügen Sie eine verschachtelte Klasse RetainedFragment hinzu, die die Fragement-Klasse erweitert und keine eigene Benutzeroberfläche hat. Fügen Sie dem onCreate-Ereignis dieses Fragments setRetainInstance (true) hinzu. Stellen Sie Verfahren zum Einstellen und Abrufen Ihrer Daten bereit.
In onCreate () der äußersten Aktivitätsklasse wird das RetainedFragment behandelt: Verweisen Sie darauf, wenn es bereits vorhanden ist (falls die Aktivität neu gestartet wird). erstellen und hinzufügen, wenn es nicht existiert; Wenn es bereits vorhanden war, holen Sie sich Daten aus dem RetainedFragment und stellen Sie Ihre Benutzeroberfläche mit diesen Daten ein.
Initiieren Sie die AsyncTask über die Benutzeroberfläche
Fügen Sie einen bestimmten Fortschrittsbalken hinzu und codieren Sie ihn:
Der gesamte Code für das obige Verfahren
Aktivitätslayout.
Die Aktivität mit: untergeordneter AsyncTask-Innenklasse; Unterklasse RetainedFragment innere Klasse, die Änderungen der Laufzeitkonfiguration verarbeitet (z. B. wenn der Benutzer den Bildschirm dreht); und einen bestimmten Fortschrittsbalken, der in regelmäßigen Abständen aktualisiert wird. ...
In diesem Beispiel die Bibliotheksfunktion (auf die oben mit dem expliziten Paketpräfix com.example.standardapplibrary.android.Network verwiesen wird), die echte Arbeit leistet ...
Fügen Sie der AndroidManifest.xml alle Berechtigungen hinzu, die für Ihre Hintergrundaufgabe erforderlich sind ...
Fügen Sie Ihre Aktivität zu AndroidManifest.xml hinzu ...
quelle
Kürzlich habe ich hier eine gute Lösung gefunden . Es basiert auf dem Speichern eines Aufgabenobjekts über RetainConfiguration. Meiner Ansicht nach ist die Lösung sehr elegant und ich habe begonnen, sie zu verwenden. Sie müssen nur Ihre Asynctask aus der Basetask verschachteln und das ist alles.
quelle
Basierend auf der Antwort von @Alex Lockwood und den Antworten von @William & @quickdraw mcgraw in diesem Beitrag: Wie man mit Handler-Nachrichten umgeht, wenn Aktivität / Fragment angehalten wird , habe ich eine generische Lösung geschrieben.
Auf diese Weise wird die Rotation behandelt, und wenn die Aktivität während der Ausführung der asynchronen Aufgabe in den Hintergrund tritt, erhält die Aktivität die Rückrufe (onPreExecute, onProgressUpdate, onPostExecute & onCancelled), sobald sie fortgesetzt wird, sodass keine IllegalStateException ausgelöst wird (siehe Handhabung des Handlers) Nachrichten, wenn Aktivität / Fragment angehalten wird ).
Es wäre großartig, dasselbe zu haben, aber mit generischen Argumenttypen wie einer AsyncTask (z. B. AsyncTaskFragment <Parameter, Fortschritt, Ergebnis>), aber ich habe es nicht schnell geschafft und im Moment keine Zeit. Wenn jemand die Verbesserung vornehmen möchte, fühlen Sie sich bitte frei!
Der Code:
Sie benötigen den PauseHandler:
Beispielnutzung:
quelle
Hierfür können Sie Loader verwenden. Überprüfen Sie Doc hier
quelle
Für diejenigen, die Fragmenten ausweichen möchten, können Sie die AsyncTask bei Änderungen der Ausrichtung mithilfe von onRetainCustomNonConfigurationInstance () und einigen Verkabelungen beibehalten .
(Beachten Sie, dass diese Methode die Alternative zu der veralteten onRetainNonConfigurationInstance () ist. )
Diese Lösung scheint jedoch nicht häufig erwähnt zu werden. Ich habe ein einfaches Laufbeispiel geschrieben, um es zu veranschaulichen.
Prost!
quelle
Ich habe eine Bibliothek implementiert , die Probleme mit der Unterbrechung und Wiederherstellung von Aktivitäten lösen kann, während Ihre Aufgabe ausgeführt wird.
Sie sollten
AsmykPleaseWaitTask
und implementierenAsmykBasicPleaseWaitActivity
. Ihre Aktivität und Hintergrundaufgabe funktionieren einwandfrei, auch wenn Sie den Bildschirm drehen und zwischen Anwendungen wechselnquelle
SCHNELLE UMARBEIT (nicht empfohlen)
Um zu vermeiden, dass eine Aktivität zerstört und selbst erstellt wird, müssen Sie Ihre Aktivität in der Manifestdatei deklarieren: android: configChanges = "Ausrichtung | Tastaturversteckt | Bildschirmgröße"
Wie in den Dokumenten erwähnt
quelle