Umgang mit Lebenszyklen mit lebenszyklusbezogenen Komponenten Teil von Android Jetpack
Lebenszyklusbewusste Komponenten führen Aktionen als Reaktion auf eine Änderung des Lebenszyklusstatus einer anderen Komponente, wie z. B. Aktivitäten und Fragmente. Diese -Komponenten helfen Ihnen, besser organisierten und oft leichteren Code zu erstellen. die einfacher zu verwalten ist.
Ein gängiges Muster ist die Implementierung der Aktionen der abhängigen Komponenten in der Lebenszyklusmethoden von Aktivitäten und Fragmenten. Dieses Muster führt jedoch zu einer schlechte Strukturierung des Codes und die Zunahme von Fehlern. Durch die Verwendung von können Sie den Code abhängiger Komponenten Lebenszyklusmethoden und die Komponenten selbst.
Die androidx.lifecycle
-Paket enthält Klassen und Schnittstellen, mit denen Sie lebenszyklusorientierte
Komponenten, also Komponenten, die ihre
basierend auf dem aktuellen Lebenszyklusstatus einer Aktivität oder eines Fragments.
Die meisten im Android-Framework definierten App-Komponenten haben Lebenszyklen angehängt. Lebenszyklen werden vom Betriebssystem oder den Framework-Code, der in Ihrem Prozess ausgeführt wird. Sie sind das Herzstück der Funktionsweise von Android und Ihre Anwendung muss diese berücksichtigen. Andernfalls können Speicherlecks oder sogar App-Abstürze.
Angenommen, wir haben eine Aktivität, bei der der Gerätestandort auf dem Bildschirm angezeigt wird. A Beispiel für eine gängige Implementierung:
Kotlin
internal class MyLocationListener( private val context: Context, private val callback: (Location) -> Unit ) { fun start() { // connect to system location service } fun stop() { // disconnect from system location service } } class MyActivity : AppCompatActivity() { private lateinit var myLocationListener: MyLocationListener override fun onCreate(...) { myLocationListener = MyLocationListener(this) { location -> // update UI } } public override fun onStart() { super.onStart() myLocationListener.start() // manage other components that need to respond // to the activity lifecycle } public override fun onStop() { super.onStop() myLocationListener.stop() // manage other components that need to respond // to the activity lifecycle } }
Java
class MyLocationListener { public MyLocationListener(Context context, Callback callback) { // ... } void start() { // connect to system location service } void stop() { // disconnect from system location service } } class MyActivity extends AppCompatActivity { private MyLocationListener myLocationListener; @Override public void onCreate(...) { myLocationListener = new MyLocationListener(this, (location) -> { // update UI }); } @Override public void onStart() { super.onStart(); myLocationListener.start(); // manage other components that need to respond // to the activity lifecycle } @Override public void onStop() { super.onStop(); myLocationListener.stop(); // manage other components that need to respond // to the activity lifecycle } }
Auch wenn dieses Beispiel gut aussieht,
haben Sie in einer echten App zu viele
Aufrufe, die die UI und andere Komponenten als Reaktion auf den aktuellen Status verwalten
des Lebenszyklus. Bei der Verwaltung mehrerer Komponenten
Code in Lebenszyklusmethoden wie onStart()
und
onStop()
, was ihre Verwaltung erschwert.
Darüber hinaus gibt es keine Garantie, dass die Komponente vor der Aktivität oder
Fragment gestoppt. Dies gilt insbesondere, wenn wir eine
lang andauernden Vorgang, z. B. eine Konfigurationsprüfung in onStart()
. Dies kann zu einer Race-Bedingung führen, bei der die onStop()
-Methode vor dem onStart()
beendet wird, wodurch die Komponente länger als vorgesehen aktiv bleibt.
erforderlich.
Kotlin
class MyActivity : AppCompatActivity() { private lateinit var myLocationListener: MyLocationListener override fun onCreate(...) { myLocationListener = MyLocationListener(this) { location -> // update UI } } public override fun onStart() { super.onStart() Util.checkUserStatus { result -> // what if this callback is invoked AFTER activity is stopped? if (result) { myLocationListener.start() } } } public override fun onStop() { super.onStop() myLocationListener.stop() } }
Java
class MyActivity extends AppCompatActivity { private MyLocationListener myLocationListener; public void onCreate(...) { myLocationListener = new MyLocationListener(this, location -> { // update UI }); } @Override public void onStart() { super.onStart(); Util.checkUserStatus(result -> { // what if this callback is invoked AFTER activity is stopped? if (result) { myLocationListener.start(); } }); } @Override public void onStop() { super.onStop(); myLocationListener.stop(); } }
Die androidx.lifecycle
-Paket enthält Klassen und Schnittstellen, mit denen Sie diese Probleme in einem
belastbar und isoliert.
Lebenszyklus
Lifecycle
ist ein Kurs
der die Informationen zum Lebenszyklusstatus einer Komponente enthält, z. B.
Aktivität oder ein Fragment) und ermöglicht es anderen Objekten, diesen Status zu beobachten.
In Lifecycle
werden zwei Haupt-
Aufzählungen, um den Lebenszyklusstatus der zugehörigen Komponente zu verfolgen:
- Veranstaltung
- Die Lebenszyklusereignisse, die vom Framework und vom
Klasse
Lifecycle
. Diese -Ereignisse den Callback-Ereignissen in Aktivitäten und Fragmenten. - Bundesland
- Der aktuelle Status der Komponente, die vom
Objekt
Lifecycle
.
Stellen Sie sich die Zustände als Knoten eines Graphen und die Ereignisse als Ränder zwischen dieser Knoten.
Eine Klasse kann den Lebenszyklusstatus der Komponente überwachen,
DefaultLifecycleObserver
und entsprechende Methoden wie onCreate
, onStart
usw. überschreiben.
Dann können Sie einen Beobachter hinzufügen, indem Sie die Methode
addObserver()
von Lifecycle
und übergeben eine Instanz Ihres Beobachters, wie unten
Beispiel:
Kotlin
class MyObserver : DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { connect() } override fun onPause(owner: LifecycleOwner) { disconnect() } } myLifecycleOwner.getLifecycle().addObserver(MyObserver())
Java
public class MyObserver implements DefaultLifecycleObserver { @Override public void onResume(LifecycleOwner owner) { connect() } @Override public void onPause(LifecycleOwner owner) { disconnect() } } myLifecycleOwner.getLifecycle().addObserver(new MyObserver());
Im obigen Beispiel implementiert das myLifecycleOwner
-Objekt den Parameter
LifecycleOwner
die im folgenden Abschnitt erläutert wird.
LifecycleOwner
LifecycleOwner
ist ein
Schnittstelle für eine einzelne Methode, die anzeigt, dass die Klasse über ein
Lifecycle
Es hat eine
Methode
getLifecycle()
,
der von der Klasse implementiert werden muss.
Wenn Sie den Lebenszyklus einer ganzen Anwendung verwalten möchten
finden Sie unter
ProcessLifecycleOwner
Diese Schnittstelle abstrahiert die Inhaberschaft eines
Lifecycle
von Einzelpersonen
wie Fragment
und AppCompatActivity
und ermöglicht das Schreiben von Komponenten,
mit ihnen zusammenzuarbeiten. Jede benutzerdefinierte Anwendungsklasse kann den
LifecycleOwner
.
Komponenten, die
DefaultLifecycleObserver
nahtlos mit Komponenten arbeiten,
LifecycleOwner
weil ein Inhaber einen Lebenszyklus bereitstellen kann, den ein Beobachter registrieren kann.
ansehen.
Für das Beispiel mit dem Standort-Tracking können wir die MyLocationListener
-Klasse
DefaultLifecycleObserver
implementieren
und dann mit der Methode
Lifecycle
in der Methode onCreate()
Dadurch können die
MyLocationListener
-Klasse als eigenständig, d. h., die Logik zur
Stattdessen wird in MyLocationListener
deklariert, dass auf Änderungen des Lebenszyklusstatus reagiert wird.
der Aktivität. Wenn die einzelnen Komponenten ihre eigene Logik speichern,
Aktivitäten und Fragmentierungslogik einfacher zu verwalten.
Kotlin
class MyActivity : AppCompatActivity() { private lateinit var myLocationListener: MyLocationListener override fun onCreate(...) { myLocationListener = MyLocationListener(this, lifecycle) { location -> // update UI } Util.checkUserStatus { result -> if (result) { myLocationListener.enable() } } } }
Java
class MyActivity extends AppCompatActivity { private MyLocationListener myLocationListener; public void onCreate(...) { myLocationListener = new MyLocationListener(this, getLifecycle(), location -> { // update UI }); Util.checkUserStatus(result -> { if (result) { myLocationListener.enable(); } }); } }
Ein häufiger Anwendungsfall besteht darin,
das Aufrufen bestimmter Callbacks zu vermeiden, wenn der
Lifecycle
ist schlecht
Bundesstaat in Bearbeitung. Wenn der Callback z. B. eine Fragment-Transaktion nach
wenn der Aktivitätsstatus gespeichert ist, würde das einen Absturz auslösen.
rufen Sie diesen Callback auf.
Um diesen Anwendungsfall zu vereinfachen,
Lifecycle
-Klasse ermöglicht
andere Objekte, um den aktuellen Status abzufragen.
Kotlin
internal class MyLocationListener( private val context: Context, private val lifecycle: Lifecycle, private val callback: (Location) -> Unit ): DefaultLifecycleObserver { private var enabled = false override fun onStart(owner: LifecycleOwner) { if (enabled) { // connect } } fun enable() { enabled = true if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { // connect if not connected } } override fun onStop(owner: LifecycleOwner) { // disconnect if connected } }
Java
class MyLocationListener implements DefaultLifecycleObserver { private boolean enabled = false; public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) { ... } @Override public void onStart(LifecycleOwner owner) { if (enabled) { // connect } } public void enable() { enabled = true; if (lifecycle.getCurrentState().isAtLeast(STARTED)) { // connect if not connected } } @Override public void onStop(LifecycleOwner owner) { // disconnect if connected } }
Mit dieser Implementierung ist unsere LocationListener
-Klasse vollständig
Lebenszyklus-bewusst ist. Wenn die LocationListener
aus einer anderen Aktivität benötigt wird
oder Fragment, müssen wir es nur initialisieren. Die gesamte Einrichtung und das Entfernen
werden von der Klasse selbst verwaltet.
Wenn eine Bibliothek Klassen bereitstellt, die mit dem Android-Lebenszyklus funktionieren müssen, empfehlen, Lebenszyklus-bewusste Komponenten zu verwenden. Ihre Bibliothekskunden können diese Komponenten ohne manuelle Lebenszyklusverwaltung Clientseite.
Benutzerdefinierten LifecycleOwner implementieren
Fragmente und Aktivitäten in der Support Library 26.1.0 und höher werden bereits implementiert.
LifecycleOwner
.
Wenn Sie einen benutzerdefinierten Kurs haben,
LifecycleOwner
, ich
kann das
Lebenszyklusregistrierung
Klasse, aber Sie müssen Termine an diesen Kurs weiterleiten, wie im Folgenden gezeigt:
Codebeispiel:
Kotlin
class MyActivity : Activity(), LifecycleOwner { private lateinit var lifecycleRegistry: LifecycleRegistry override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleRegistry = LifecycleRegistry(this) lifecycleRegistry.markState(Lifecycle.State.CREATED) } public override fun onStart() { super.onStart() lifecycleRegistry.markState(Lifecycle.State.STARTED) } override fun getLifecycle(): Lifecycle { return lifecycleRegistry } }
Java
public class MyActivity extends Activity implements LifecycleOwner { private LifecycleRegistry lifecycleRegistry; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); lifecycleRegistry = new LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override public void onStart() { super.onStart(); lifecycleRegistry.markState(Lifecycle.State.STARTED); } @NonNull @Override public Lifecycle getLifecycle() { return lifecycleRegistry; } }
Best Practices für lebenszyklusbewusste Komponenten
- Halten Sie Ihre UI-Controller (Aktivitäten und Fragmente) so schlank wie möglich. Sie
sollten nicht versuchen, an ihre eigenen Daten zu gelangen; verwenden Sie stattdessen eine
ViewModel
dazu, und beobachten Sie einenLiveData
um die Änderungen in den Ansichten widerzuspiegeln. - Versuchen Sie, datengesteuerte Benutzeroberflächen zu schreiben, für die Ihr UI-Controller dafür verantwortlich ist,
Aktualisieren Sie die Ansichten, wenn sich Daten ändern, oder informieren Sie Nutzer über Aktionen
ViewModel
- Setzen Sie Ihre Datenlogik in Ihre
Klasse
ViewModel
.ViewModel
soll ausgeliefert werden als Verbindungselement zwischen dem UI-Controller und dem Rest der Anwendung. Seien aber nicht unbedingtViewModel
dafür verantwortlich, Daten abzurufen (z. B. aus einem Netzwerk). StattdessenViewModel
sollte Folgendes aufrufen: um die Daten abzurufen, und geben das Ergebnis an die UI-Controller. - Mit der Datenbindung lässt sich Folgendes verwalten: eine saubere Schnittstelle zwischen den Ansichten und dem UI-Controller. So können Sie Machen Sie Ihre Ansichten deklarativer und minimieren Sie den Aktualisierungscode, den Sie aktualisieren müssen. Aktivitäten und Fragmente notieren. Wenn Sie es lieber in der Java- eine Bibliothek wie Buttermesser, um Textbausteine zu vermeiden und haben eine bessere Abstraktion.
- Wenn Ihre Benutzeroberfläche komplex ist, sollten Sie eine Vortragender zum Verarbeiten von UI-Änderungen. Dies mag eine mühsame Aufgabe sein, um Ihre UI-Komponenten einfacher zu testen.
- Verweisen Sie nicht auf
View
oderActivity
. Kontext inViewModel
. WennViewModel
die Aktivität überdauert (im Fall von Konfigurationsänderungen), und Ihre Aktivitäten nicht ordnungsgemäß entsorgt werden. - Kotlin-Koroutinen zur Verwaltung verwenden lang andauernde Aufgaben und andere Vorgänge, die asynchron ausgeführt werden können.
Anwendungsfälle für lebenszyklusbezogene Komponenten
Komponenten, die den Lebenszyklus berücksichtigen, können die Verwaltung von Lebenszyklen erheblich vereinfachen. in unterschiedlichen Fällen. Hier einige Beispiele:
- Zwischen groben und detaillierten Standortaktualisierungen wechseln Verwenden Sie
Lebenszyklus-bewusste Komponenten, um präzise Standortaktualisierungen zu ermöglichen, während Ihre
Standort-App ist sichtbar und wechselt zu ungenauen Updates, wenn die App
im Hintergrund.
LiveData
, eine Komponente, die den Lebenszyklus berücksichtigt, Ermöglicht Ihrer App, die Benutzeroberfläche automatisch zu aktualisieren, wenn sich der Nutzer ändert Standorte. - Stoppen und Starten der Video-Pufferung Verwenden Sie Lebenszyklus-orientierte Komponenten, das Video wird so schnell wie möglich gepuffert, aber die Wiedergabe verschieben, bis die App vollständig geladen ist begonnen. Sie können auch Komponenten verwenden, die den Lebenszyklus berücksichtigen, um die Zwischenspeicherung zu beenden. wenn Ihre App gelöscht wird.
- Netzwerkverbindung wird gestartet und beendet. Lebenszyklusbewusste Komponenten nutzen, Live-Aktualisierung (Streaming) von Netzwerkdaten aktivieren, während sich eine App im und automatisch pausiert, wenn die App Hintergrund.
- Animierte Drawables pausieren und fortsetzen Lebenszyklusbewusste Komponenten nutzen, animierte Drawables pausieren, wenn die App im Hintergrund läuft Du kannst die Drawables wieder aktivieren, wenn die App im Vordergrund ausgeführt wird.
Umgang mit Stoppereignissen
Wenn ein Lifecycle
zu einem AppCompatActivity
gehört
oder Fragment
, die Lifecycle
Statusänderungen zu
CREATED
und
ON_STOP
wird ausgelöst, wenn AppCompatActivity
oder
onSaveInstanceState()
von Fragment
aufgerufen wird.
Wenn der Status eines Fragment
- oder AppCompatActivity
-Elements über
onSaveInstanceState()
, es ist die Benutzeroberfläche
gilt als unveränderlich bis
ON_START
ist
aufgerufen. Der Versuch, die Benutzeroberfläche nach dem Speichern des Status zu ändern, führt wahrscheinlich
Uneinheitlichkeiten im Navigationsstatus deiner App, weshalb FragmentManager
eine Ausnahme auslöst, wenn die App eine
FragmentTransaction
nach dem Speichern des Status. Weitere Informationen finden Sie unter
commit()
.
LiveData
verhindert, dass dieser Grenzfall sofort einsatzbereit ist,
den Beobachter nicht mehr aufrufen,
wenn der zugehörige Lifecycle
ist nicht mindestens
STARTED
Hinter den Kulissen ruft er
isAtLeast()
bevor der Beobachter aufgerufen wird.
Die onStop()
-Methode von AppCompatActivity
wird leider nach aufgerufen.
onSaveInstanceState()
,
Dadurch entsteht eine Lücke, in der Änderungen des UI-Status zwar nicht zulässig sind,
Lifecycle
wurde noch nicht in den
CREATED
Bundesstaat.
Um dieses Problem zu vermeiden, hat die Klasse Lifecycle
in Version beta2
und kennzeichnen Sie den Bundesstaat
CREATED
ohne das Ereignis auszulösen, sodass jeder Code, der die aktuelle
erhält den tatsächlichen Wert, auch wenn das Ereignis erst gesendet wird, wenn onStop()
vom System aufgerufen wird.
Leider bringt diese Lösung zwei größere Probleme mit sich:
- Auf API-Level 23 und niedriger speichert das Android-System den Zustand eines
auch dann, wenn sie teilweise durch eine andere Aktivität abgedeckt ist. In anderen
ruft das Android-System
onSaveInstanceState()
auf. ruft aber nicht unbedingtonStop()
auf. Dadurch entsteht eine potenzielle langen Intervall, bei dem der Beobachter noch glaubt, dass der Lebenszyklus aktiv ist auch wenn sein UI-Status nicht geändert werden kann. - Jede Klasse, die ein ähnliches Verhalten wie die
LiveData
muss die Problemumgehung implementieren, die vonLifecycle
Versionbeta 2
und niedriger.
Weitere Informationen
Weitere Informationen zum Umgang mit Lebenszyklen mit lebenszyklusbezogenen Komponenten erhalten Sie in den folgenden zusätzlichen Ressourcen.
Produktproben
- <ph type="x-smartling-placeholder"></ph> Grundlegendes Beispiel zu Android-Architekturkomponenten
- <ph type="x-smartling-placeholder"></ph> Sunflower, eine Demo-App, die Best Practices mit Architekturkomponenten
Codelabs
Blogs
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- LiveData-Übersicht
- Kotlin-Koroutinen mit lebenszyklusbezogenen Komponenten verwenden
- Modul „Saved State“ für ViewModel