Leichte Abweichung von meinem anderen Beitrag
Grundsätzlich habe ich eine Nachricht Handler
in meinem, Fragment
die eine Reihe von Nachrichten empfängt, die dazu führen können, dass Dialoge geschlossen oder angezeigt werden.
Wenn die App in den Hintergrund gestellt wird, erhalte ich eine, onPause
aber dann kommen meine Nachrichten immer noch wie erwartet durch. Da ich jedoch Fragmente verwende, kann ich Dialoge nicht einfach schließen und anzeigen, da dies zu einem führt IllegalStateException
.
Ich kann nicht einfach entlassen oder stornieren, um einen Staatsverlust zuzulassen.
Angesichts der Tatsache, dass ich eine Handler
habe, frage ich mich, ob es einen empfohlenen Ansatz gibt, wie ich mit Nachrichten in einem angehaltenen Zustand umgehen soll.
Eine mögliche Lösung, die ich in Betracht ziehe, besteht darin, die eingehenden Nachrichten während der Pause aufzuzeichnen und sie auf einem abzuspielen onResume
. Dies ist etwas unbefriedigend und ich denke, dass es etwas im Rahmen geben muss, um dies eleganter zu handhaben.
Antworten:
Obwohl das Android-Betriebssystem anscheinend keinen Mechanismus hat, der Ihr Problem ausreichend behebt, glaube ich, dass dieses Muster eine relativ einfach zu implementierende Problemumgehung bietet.
Die folgende Klasse ist ein Wrapper
android.os.Handler
, der Nachrichten puffert, wenn eine Aktivität angehalten wird, und sie bei der Wiedergabe wiedergibt.Stellen Sie sicher, dass jeder Code, der einen Fragmentstatus asynchron ändert (z. B. Festschreiben, Entlassen), nur von einer Nachricht im Handler aufgerufen wird.
Leiten Sie Ihren Handler aus der
PauseHandler
Klasse ab.Wann immer Ihre Aktivität einen
onPause()
Anruf erhältPauseHandler.pause()
und zumonResume()
AnrufPauseHandler.resume()
.Ersetzen Sie Ihre Implementierung des Handlers
handleMessage()
durchprocessMessage()
.Stellen Sie eine einfache Implementierung bereit,
storeMessage()
die immer zurückkehrttrue
.Im Folgenden finden Sie ein einfaches Beispiel für die Verwendung der
PausedHandler
Klasse.Auf Knopfdruck wird eine verzögerte Nachricht an den Handler gesendet.
Wenn der Handler die Nachricht empfängt (im UI-Thread), wird a angezeigt
DialogFragment
.Wenn die
PausedHandler
Klasse nicht verwendet wurde, wird eine IllegalStateException angezeigt, wenn die Home-Taste nach dem Drücken der Test-Taste gedrückt wurde, um den Dialog zu starten.Ich habe
storeMessage()
derPausedHandler
Klasse eine Methode hinzugefügt, falls Nachrichten sofort verarbeitet werden sollen, auch wenn die Aktivität angehalten wird. Wenn eine Nachricht behandelt wird, sollte false zurückgegeben werden und die Nachricht wird verworfen.quelle
resume
MethodesendMessage(msg)
technisch verwendet, können andere Threads unmittelbar vor (oder zwischen den Iterationen der Schleife) Nachrichten in die Warteschlange stellen, was bedeutet, dass die gespeicherten Nachrichten mit neuen Nachrichten verschachtelt werden können. Ich bin mir nicht sicher, ob es eine große Sache ist. Vielleicht würde die VerwendungsendMessageAtFrontOfQueue
(und natürlich das Rückwärtslaufen) dieses Problem lösen?Eine etwas einfachere Version von Quickdraws ausgezeichnetem PauseHandler ist
Es wird davon ausgegangen, dass Sie immer Offline-Nachrichten zur Wiedergabe speichern möchten. Und stellt die Aktivität als Eingabe bereit,
#processMessages
damit Sie sie nicht in der Unterklasse verwalten müssen.quelle
resume()
undpause()
undhandleMessage
synchronized
?Hier ist eine etwas andere Methode, um das Problem der Ausführung von Fragment-Commits in einer Rückruffunktion und der Vermeidung des IllegalStateException-Problems anzugehen.
Erstellen Sie zunächst eine benutzerdefinierte ausführbare Schnittstelle.
Erstellen Sie als Nächstes ein Fragment für die Verarbeitung der MyRunnable-Objekte. Wenn das MyRunnable-Objekt nach dem Anhalten der Aktivität erstellt wurde, z. B. wenn der Bildschirm gedreht wird oder der Benutzer die Home-Taste drückt, wird es zur späteren Verarbeitung mit einem neuen Kontext in eine Warteschlange gestellt. Die Warteschlange überlebt alle Konfigurationsänderungen, da die setRetain-Instanz auf true gesetzt ist. Die Methode runProtected wird im UI-Thread ausgeführt, um eine Racebedingung mit dem Flag isPaused zu vermeiden.
Schließlich kann das Fragment in einer Hauptanwendung wie folgt verwendet werden:
quelle
In meinen Projekten verwende ich das Beobachter-Entwurfsmuster, um dies zu lösen. In Android sind Rundfunkempfänger und -absichten eine Implementierung dieses Musters.
Ich erstelle einen BroadcastReceiver, den ich in onResume von fragment / activity registriere und in onPause von fragment / activity abhebe . In der BroadcastReceiver -Methode onReceive habe ich den gesamten Code eingefügt , der ausgeführt werden muss, wenn - der BroadcastReceiver - eine Absicht (Nachricht) empfangen hat, die im Allgemeinen an Ihre App gesendet wurde. Um die Selektivität für die Art der Absichten zu erhöhen, die Ihr Fragment empfangen kann, können Sie einen Absichtsfilter wie im folgenden Beispiel verwenden.
Ein Vorteil dieses Ansatzes ist, dass die Absicht (Nachricht) von überall in Ihrer App gesendet werden kann (ein Dialogfeld, das über Ihrem Fragment geöffnet wurde, eine asynchrone Aufgabe, ein anderes Fragment usw.). Parameter können sogar als Absichts-Extras übergeben werden.
Ein weiterer Vorteil ist, dass dieser Ansatz mit jeder Android-API-Version kompatibel ist, da BroadcastReceivers und Intents auf API-Ebene 1 eingeführt wurden.
Sie müssen keine speziellen Berechtigungen für die Manifestdatei Ihrer App einrichten, es sei denn, Sie möchten sendStickyBroadcast verwenden (wo Sie BROADCAST_STICKY hinzufügen müssen).
quelle