Konzepte und Jetpack Compose-Implementierung
Wenn ein Nutzer durch Ihre App navigiert, sie verlässt und wieder aufruft, durchlaufen die Activity-Instanzen in Ihrer App verschiedene Status in ihrem Lebenszyklus.
Die Klasse Activity bietet eine Reihe von Callbacks, mit denen die Aktivität darüber informiert wird, wenn sich ein Status ändert oder das System eine Aktivität erstellt, beendet oder fortsetzt oder den Prozess beendet, in dem sich die Aktivität befindet.
In den Methoden für Lebenszyklus-Callbacks können Sie deklarieren, wie sich Ihre Aktivität verhält, wenn der Nutzer sie verlässt und wieder aufruft. Wenn Sie beispielsweise einen Streaming-Videoplayer entwickeln, können Sie das Video pausieren und die Netzwerkverbindung beenden, wenn der Nutzer zu einer anderen App wechselt. Wenn der Nutzer zurückkehrt, können Sie die Netzwerkverbindung wiederherstellen und dem Nutzer ermöglichen, das Video an derselben Stelle fortzusetzen.
Mit jedem Callback können Sie bestimmte Aufgaben ausführen, die für eine bestimmte Zustandsänderung geeignet sind. Wenn Sie die richtigen Aufgaben zur richtigen Zeit ausführen und Übergänge richtig verarbeiten, wird Ihre App robuster und leistungsfähiger. Eine gute Implementierung der Lebenszyklus-Callbacks kann beispielsweise dazu beitragen, dass Ihre App Folgendes vermeidet:
- Die App stürzt ab, wenn der Nutzer einen Anruf erhält oder zu einer anderen App wechselt, während er Ihre App verwendet.
- Verbrauch wertvoller Systemressourcen, wenn der Nutzer das Gerät nicht aktiv verwendet.
- Der Fortschritt des Nutzers geht verloren, wenn er Ihre App verlässt und später wieder aufruft.
- Die App stürzt ab oder der Fortschritt des Nutzers geht verloren, wenn der Bildschirm zwischen Quer- und Hochformat gedreht wird.
In diesem Dokument wird der Aktivitätslebenszyklus im Detail beschrieben. Das Dokument beginnt mit einer Beschreibung des Lebenszyklusmodells. Anschließend werden die einzelnen Callbacks erläutert: Was passiert intern während der Ausführung und was müssen Sie während der Ausführung implementieren?
Anschließend wird kurz die Beziehung zwischen dem Aktivitätsstatus und der Anfälligkeit eines Prozesses für das Beenden durch das System erläutert. Abschließend werden mehrere Themen im Zusammenhang mit Übergängen zwischen Aktivitätsstatus behandelt.
Informationen zum Umgang mit Lebenszyklen, einschließlich Best Practices, finden Sie unter Lebenszyklen mit lebenszyklusbewussten Komponenten verarbeiten und UI-Zustände speichern. Informationen zum Erstellen einer robusten App in Produktionsqualität mit Aktivitäten in Kombination mit Architekturkomponenten finden Sie im Leitfaden zur App-Architektur.
Konzepte für den Aktivitätslebenszyklus
Für die Übergänge zwischen den Phasen des Aktivitätslebenszyklus bietet die Klasse Activity eine Reihe von sechs Callbacks: onCreate, onStart, onResume, onPause, onStop und onDestroy. Das System ruft jeden dieser Callbacks auf, wenn die Aktivität in einen neuen Status wechselt.
Abbildung 1 zeigt eine visuelle Darstellung dieses Paradigmas.
Wenn der Nutzer die Aktivität verlässt, ruft das System Methoden auf, um die Aktivität zu beenden. In einigen Fällen wird die Aktivität nur teilweise beendet und verbleibt weiterhin im Arbeitsspeicher, z. B. wenn der Nutzer zu einer anderen App wechselt. In diesen Fällen kann die Aktivität weiterhin in den Vordergrund zurückkehren.
Wenn der Nutzer zur Aktivität zurückkehrt, wird sie an der Stelle fortgesetzt, an der er sie verlassen hat. Mit wenigen Ausnahmen dürfen Apps keine Aktivitäten starten, wenn sie im Hintergrund ausgeführt werden.
Die Wahrscheinlichkeit, dass das System einen bestimmten Prozess beendet, hängt vom Status der Aktivität zu diesem Zeitpunkt ab. Weitere Informationen zum Zusammenhang zwischen dem Aktivitätsstatus und der Wahrscheinlichkeit, dass eine App aus dem Arbeitsspeicher entfernt wird, finden Sie im Abschnitt Aktivitätsstatus und Entfernen aus dem Arbeitsspeicher.
Je nach Komplexität Ihrer Aktivität müssen Sie wahrscheinlich nicht alle Lebenszyklusmethoden implementieren. Es ist jedoch wichtig, dass Sie die einzelnen Optionen verstehen und diejenigen implementieren, die dafür sorgen, dass sich Ihre App so verhält, wie Nutzer es erwarten.
Lebenszyklus-Callbacks
Dieser Abschnitt enthält konzeptionelle Informationen und Informationen zur Implementierung der Callback-Methoden, die während des Aktivitätslebenszyklus verwendet werden.
Einige Aktionen gehören zu den Methoden des Aktivitätslebenszyklus. Platzieren Sie Code, der die Aktionen einer abhängigen Komponente implementiert, jedoch in der Komponente und nicht in der Methode des Aktivitätslebenszyklus. Dazu müssen Sie die abhängige Komponente so gestalten, dass sie den Lebenszyklus berücksichtigt. Informationen dazu, wie Sie Ihre abhängigen Komponenten lebenszyklusbewusst machen, finden Sie unter Lebenszyklen mit lebenszyklusbewussten Komponenten verarbeiten.
onCreate
Sie müssen diesen Callback implementieren, der ausgelöst wird, wenn das System die Aktivität zum ersten Mal erstellt. Nach der Erstellung hat die Aktivität den Status Erstellt. Führen Sie in der Methode onCreate die grundlegende Anwendungsstartlogik aus, die nur einmal für die gesamte Lebensdauer der Aktivität ausgeführt wird.
Ihre Implementierung von onCreate könnte beispielsweise Daten an Listen binden, die Aktivität mit einem ViewModel verknüpfen und einige Variablen im Klassenbereich instanziieren. Diese Methode empfängt den Parameter savedInstanceState, ein Bundle-Objekt, das den zuvor gespeicherten Status der Aktivität enthält. Wenn die Aktivität noch nie vorhanden war, ist der Wert des Bundle-Objekts null.
Wenn Sie eine lebenszyklusbewusste Komponente haben, die mit dem Lebenszyklus Ihrer Aktivität verbunden ist, empfängt sie das Ereignis ON_CREATE. Die mit @OnLifecycleEvent annotierte Methode wird aufgerufen, damit Ihre lebenszyklusbewusste Komponente den erforderlichen Einrichtungscode für den erstellten Status ausführen kann.
Das folgende Beispiel für die Methode onCreate zeigt die grundlegende Einrichtung für die Aktivität, z. B. das Deklarieren der Benutzeroberfläche (definiert in einer XML-Layoutdatei), das Definieren von Mitgliedsvariablen und das Konfigurieren einiger Elemente der Benutzeroberfläche. In diesem Beispiel wird die Ressourcen-ID R.layout.main_activity der Datei an setContentView übergeben.
Kotlin
lateinit var textView: TextView
// Some transient state for the activity instance.
var gameState: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
// Call the superclass onCreate to complete the creation of
// the activity, like the view hierarchy.
super.onCreate(savedInstanceState)
// Recover the instance state.
gameState = savedInstanceState?.getString(GAME_STATE_KEY)
// Set the user interface layout for this activity.
// The layout is defined in the project res/layout/main_activity.xml file.
setContentView(R.layout.main_activity)
// Initialize member TextView so it is available later.
textView = findViewById(R.id.text_view)
}
// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}
// Invoked when the activity might be temporarily destroyed; save the instance state here.
override fun onSaveInstanceState(outState: Bundle?) {
outState?.run {
putString(GAME_STATE_KEY, gameState)
putString(TEXT_VIEW_KEY, textView.text.toString())
}
// Call superclass to save any view hierarchy.
super.onSaveInstanceState(outState)
}
Java
TextView textView;
// Some transient state for the activity instance.
String gameState;
@Override
public void onCreate(Bundle savedInstanceState) {
// Call the superclass onCreate to complete the creation of
// the activity, like the view hierarchy.
super.onCreate(savedInstanceState);
// Recover the instance state.
if (savedInstanceState != null) {
gameState = savedInstanceState.getString(GAME_STATE_KEY);
}
// Set the user interface layout for this activity.
// The layout is defined in the project res/layout/main_activity.xml file.
setContentView(R.layout.main_activity);
// Initialize member TextView so it is available later.
textView = (TextView) findViewById(R.id.text_view);
}
// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}
// Invoked when the activity might be temporarily destroyed; save the instance state here.
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(GAME_STATE_KEY, gameState);
outState.putString(TEXT_VIEW_KEY, textView.getText());
// Call superclass to save any view hierarchy.
super.onSaveInstanceState(outState);
}
Alternativ zum Definieren der XML-Datei und Übergeben an setContentView können Sie neue View-Objekte in Ihrem Aktivitätscode erstellen und eine Ansichtshierarchie erstellen, indem Sie neue View-Objekte in ein ViewGroup einfügen. Anschließend verwenden Sie dieses Layout, indem Sie den Stamm-ViewGroup an setContentView übergeben. Weitere Informationen zum Erstellen einer Benutzeroberfläche finden Sie in der Dokumentation zur Benutzeroberfläche.
Ihre Aktivität bleibt nicht im Status „Erstellt“. Nachdem die Ausführung der Methode onCreate abgeschlossen ist, wechselt die Aktivität in den Status Started und das System ruft die Methoden onStart und onResume kurz nacheinander auf.
onStart
Wenn die Aktivität in den Status „Gestartet“ wechselt, ruft das System onStart auf.
Durch diesen Aufruf wird die Aktivität für den Nutzer sichtbar, während die App sich darauf vorbereitet, dass die Aktivität in den Vordergrund wechselt und interaktiv wird. In dieser Methode wird beispielsweise der Code initialisiert, der die Benutzeroberfläche verwaltet.
Wenn die Aktivität in den Status „Gestartet“ wechselt, empfängt jede lebenszyklusbewusste Komponente, die an den Lebenszyklus der Aktivität gebunden ist, das Ereignis ON_START.
Die Methode onStart wird schnell abgeschlossen und die Aktivität verbleibt wie beim Status „Erstellt“ nicht im Status „Gestartet“. Sobald dieser Callback abgeschlossen ist, wechselt die Aktivität in den Status Resumed und das System ruft die Methode onResume auf.
onResume
Wenn die Aktivität in den Status „Fortgesetzt“ wechselt, wird sie in den Vordergrund gerückt und das System ruft den onResume-Callback auf. Das ist der Status, in dem die App mit dem Nutzer interagiert. Die App bleibt in diesem Zustand, bis etwas passiert, das den Fokus von der App wegnimmt, z. B. wenn das Gerät einen Anruf empfängt, der Nutzer zu einer anderen Activity wechselt oder das Display des Geräts ausgeschaltet wird.
Wenn die Aktivität in den Status „Fortgesetzt“ wechselt, empfängt jede lebenszyklusbewusste Komponente, die an den Lebenszyklus der Aktivität gebunden ist, das Ereignis ON_RESUME. Hier können die Lebenszykluskomponenten alle Funktionen aktivieren, die ausgeführt werden müssen, während die Komponente sichtbar und im Vordergrund ist, z. B. das Starten einer Kameravorschau.
Wenn ein unterbrechendes Ereignis eintritt, wechselt die Aktivität in den Status Pausiert und das System ruft den Callback onPause auf.
Wenn die Aktivität aus dem pausierten in den fortgesetzten Status zurückkehrt, ruft das System die Methode onResume noch einmal auf. Implementieren Sie daher onResume, um Komponenten zu initialisieren, die Sie während onPause freigeben, und um alle anderen Initialisierungen auszuführen, die jedes Mal erfolgen müssen, wenn die Aktivität in den Status „Resumed“ wechselt.
Hier ist ein Beispiel für eine lebenszyklusbewusste Komponente, die auf die Kamera zugreift, wenn die Komponente das Ereignis ON_RESUME empfängt:
Kotlin
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun initializeCamera() {
if (camera == null) {
getCamera()
}
}
...
}
Java
public class CameraComponent implements LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void initializeCamera() {
if (camera == null) {
getCamera();
}
}
...
}
Im vorherigen Code wird die Kamera initialisiert, sobald LifecycleObserver das Ereignis ON_RESUME empfängt. Im Mehrfenstermodus ist deine Aktivität jedoch möglicherweise vollständig sichtbar, auch wenn sie pausiert ist. Wenn sich die App beispielsweise im Mehrfenstermodus befindet und der Nutzer auf das Fenster tippt, das Ihre Aktivität nicht enthält, wechselt Ihre Aktivität in den Status „Pausiert“.
Wenn die Kamera nur aktiv sein soll, wenn die App fortgesetzt wird (sichtbar und aktiv im Vordergrund), initialisieren Sie die Kamera nach dem oben gezeigten ON_RESUME-Ereignis. Wenn Sie die Kamera aktiv lassen möchten, während die Aktivität pausiert, aber sichtbar ist, z. B. im Mehrfenstermodus, initialisieren Sie die Kamera nach dem ON_START-Ereignis.
Wenn die Kamera jedoch aktiv ist, während Ihre Aktivität pausiert ist, kann dies den Zugriff auf die Kamera für eine andere fortgesetzte App im Mehrfenstermodus verhindern. Manchmal ist es erforderlich, die Kamera aktiv zu lassen, während deine Aktivität pausiert ist. Dies kann jedoch die allgemeine Nutzerfreundlichkeit beeinträchtigen.
Überlegen Sie sich daher genau, an welcher Stelle im Lebenszyklus es am besten ist, die Kontrolle über freigegebene Systemressourcen im Kontext des Mehrfenstermodus zu übernehmen. Weitere Informationen zur Unterstützung des Mehrfenstermodus finden Sie unter Mehrfenstermodus unterstützen.
Unabhängig davon, in welchem Build-up-Ereignis Sie einen Initialisierungsvorgang ausführen, müssen Sie die Ressource mit dem entsprechenden Lifecycle-Event freigeben. Wenn Sie etwas nach dem ON_START-Ereignis initialisieren, geben Sie es nach dem ON_STOP-Ereignis frei oder beenden Sie es. Wenn Sie nach dem ON_RESUME-Ereignis initialisieren, geben Sie die Ressource nach dem ON_PAUSE-Ereignis frei.
Im vorherigen Code-Snippet wird der Code zur Kamerainitialisierung in eine lebenszyklusbewusste Komponente eingefügt. Sie können diesen Code stattdessen direkt in die Aktivitätslebenszyklus-Callbacks wie onStart und onStop einfügen. Wir empfehlen dies jedoch nicht. Wenn Sie diese Logik einer unabhängigen, lebenszyklusbewussten Komponente hinzufügen, können Sie die Komponente in mehreren Aktivitäten wiederverwenden, ohne Code duplizieren zu müssen. Informationen zum Erstellen einer lebenszyklusbewussten Komponente finden Sie unter Lebenszyklen mit lebenszyklusbewussten Komponenten (Ansichten) verarbeiten.
onPause
Das System ruft diese Methode als ersten Hinweis darauf auf, dass der Nutzer Ihre Aktivität verlässt. Das bedeutet jedoch nicht immer, dass die Aktivität zerstört wird. Sie gibt an, dass die Aktivität nicht mehr im Vordergrund ist, aber weiterhin sichtbar ist, wenn der Nutzer den Mehrfenstermodus verwendet. Es gibt mehrere Gründe, warum eine Aktivität in diesen Status wechseln kann:
- Ein Ereignis, das die Ausführung der App unterbricht, wie im Abschnitt zum
onResume-Callback beschrieben, pausiert die aktuelle Aktivität. Das ist der häufigste Fall. - Im Mehrfenstermodus hat jeweils nur eine App den Fokus und das System pausiert alle anderen Apps.
- Wenn eine neue, halbtransparente Aktivität wie ein Dialogfeld geöffnet wird, wird die Aktivität, die sie abdeckt, pausiert. Solange die Aktivität teilweise sichtbar, aber nicht im Vordergrund ist, bleibt sie pausiert.
Wenn eine Aktivität in den Status „Pausiert“ wechselt, empfängt jede lebenszyklusbewusste Komponente, die an den Lebenszyklus der Aktivität gebunden ist, das Ereignis ON_PAUSE. Hier können die Lifecycle-Komponenten alle Funktionen beenden, die nicht ausgeführt werden müssen, wenn sich die Komponente nicht im Vordergrund befindet, z. B. das Beenden einer Kameravorschau.
Verwenden Sie die Methode onPause, um Vorgänge zu pausieren oder anzupassen, die nicht fortgesetzt werden können oder möglicherweise moderiert fortgesetzt werden, während sich Activity im Status „Pausiert“ befindet und die Sie in Kürze fortsetzen möchten.
Sie können auch die Methode onPause verwenden, um Systemressourcen, Handles für Sensoren (z. B. GPS) oder Ressourcen freizugeben, die sich auf die Akkulaufzeit auswirken, während Ihre Aktivität pausiert ist und der Nutzer sie nicht benötigt.
Wie im Abschnitt zu onResume erwähnt, kann eine pausierte Aktivität jedoch weiterhin vollständig sichtbar sein, wenn sich die App im Mehrfenstermodus befindet. Verwenden Sie onStop anstelle von onPause, um UI-bezogene Ressourcen und Vorgänge vollständig freizugeben oder anzupassen, damit der Mehrfenstermodus besser unterstützt wird.
Das folgende Beispiel für ein LifecycleObserver, das auf das Ereignis ON_PAUSE reagiert, ist das Gegenstück zum vorherigen Beispiel für das Ereignis ON_RESUME. Dabei wird die Kamera freigegeben, die nach dem Empfang des Ereignisses ON_RESUME initialisiert wird:
Kotlin
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun releaseCamera() {
camera?.release()
camera = null
}
...
}
Java
public class JavaCameraComponent implements LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void releaseCamera() {
if (camera != null) {
camera.release();
camera = null;
}
}
...
}
In diesem Beispiel wird der Code zum Auslösen der Kamera nach dem Empfang des ON_PAUSE-Ereignisses durch LifecycleObserver platziert.
Die Ausführung von onPause ist sehr kurz und bietet nicht unbedingt genügend Zeit für Speichervorgänge. Aus diesem Grund sollten Sie nicht onPause verwenden, um Anwendungs- oder Nutzerdaten zu speichern, Netzwerkaufrufe zu tätigen oder Datenbanktransaktionen auszuführen.
Diese Arbeiten werden möglicherweise nicht abgeschlossen, bevor die Methode abgeschlossen ist.
Führen Sie stattdessen Vorgänge zum Herunterfahren bei hoher Last während onStop aus. Weitere Informationen zu geeigneten Vorgängen während onStop finden Sie im nächsten Abschnitt. Weitere Informationen zum Speichern von Daten finden Sie im Abschnitt Status speichern und wiederherstellen.
Der Abschluss der onPause-Methode bedeutet nicht, dass die Aktivität den Status „Pausiert“ verlässt. Stattdessen bleibt die Aktivität in diesem Status, bis sie fortgesetzt wird oder für den Nutzer vollständig unsichtbar wird. Wenn die Aktivität fortgesetzt wird, ruft das System den onResume-Callback noch einmal auf.
Wenn die Aktivität vom Status „Pausiert“ in den Status „Fortgesetzt“ zurückkehrt, behält das System die Activity-Instanz im Arbeitsspeicher bei und ruft sie wieder auf, wenn das System onResume aufruft. In diesem Fall müssen Sie Komponenten, die während einer der Callback-Methoden bis zum Status „Resumed“ erstellt wurden, nicht neu initialisieren. Wenn die Aktivität vollständig unsichtbar wird, ruft das System onStop auf.
onStop
Wenn deine Aktivität für den Nutzer nicht mehr sichtbar ist, wechselt sie in den Status Beendet und das System ruft den onStop-Callback auf. Das kann passieren, wenn eine neu gestartete Aktivität den gesamten Bildschirm abdeckt. Das System ruft onStop auch auf, wenn die Aktivität beendet wird und kurz vor dem Beenden steht.
Wenn die Aktivität in den Status „Beendet“ wechselt, empfängt jede lebenszyklusbewusste Komponente, die an den Lebenszyklus der Aktivität gebunden ist, das Ereignis ON_STOP. Hier können die Lifecycle-Komponenten alle Funktionen beenden, die nicht ausgeführt werden müssen, wenn die Komponente nicht auf dem Bildschirm sichtbar ist.
In der onStop-Methode werden Ressourcen freigegeben oder angepasst, die nicht benötigt werden, während die App für den Nutzer nicht sichtbar ist. Ihre App kann beispielsweise Animationen pausieren oder von detaillierten zu groben Standortaktualisierungen wechseln. Wenn Sie onStop anstelle von onPause verwenden, werden UI-bezogene Aufgaben fortgesetzt, auch wenn der Nutzer Ihre Aktivität im Mehrfenstermodus ansieht.
Verwenden Sie onStop auch für relativ CPU-intensive Herunterfahrvorgänge. Wenn Sie beispielsweise keine bessere Zeit zum Speichern von Informationen in einer Datenbank finden, können Sie dies während onStop tun. Das folgende Beispiel zeigt eine Implementierung von onStop, die den Inhalt einer Notiz im Entwurf in einem nichtflüchtigen Speicher speichert:
Kotlin
override fun onStop() {
// Call the superclass method first.
super.onStop()
// Save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
val values = ContentValues().apply {
put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
}
// Do this update in background on an AsyncQueryHandler or equivalent.
asyncQueryHandler.startUpdate(
token, // int token to correlate calls
null, // cookie, not used here
uri, // The URI for the note to update.
values, // The map of column names and new values to apply to them.
null, // No SELECT criteria are used.
null // No WHERE columns are used.
)
}
Java
@Override
protected void onStop() {
// Call the superclass method first.
super.onStop();
// Save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
ContentValues values = new ContentValues();
values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());
// Do this update in background on an AsyncQueryHandler or equivalent.
asyncQueryHandler.startUpdate (
mToken, // int token to correlate calls
null, // cookie, not used here
uri, // The URI for the note to update.
values, // The map of column names and new values to apply to them.
null, // No SELECT criteria are used.
null // No WHERE columns are used.
);
}
Im vorherigen Codebeispiel wird SQLite direkt verwendet. Wir empfehlen jedoch die Verwendung von Room, einer Persistenzbibliothek, die eine Abstraktionsebene für SQLite bietet. Weitere Informationen zu den Vorteilen der Verwendung von Room und zur Implementierung von Room in Ihrer App finden Sie im Leitfaden zur Room-Persistenzbibliothek.
Wenn Ihre Aktivität in den Status „Beendet“ wechselt, bleibt das Activity-Objekt im Arbeitsspeicher: Es behält alle Status- und Mitgliedsinformationen bei, ist aber nicht an den Fenstermanager angehängt. Wenn die Aktivität fortgesetzt wird, werden diese Informationen abgerufen.
Komponenten, die während einer der Callback-Methoden bis zum Status „Resumed“ erstellt wurden, müssen nicht neu initialisiert werden. Das System behält auch den aktuellen Status für jedes View-Objekt im Layout bei. Wenn der Nutzer also Text in ein EditText-Widget eingibt, bleiben diese Inhalte erhalten und müssen nicht gespeichert und wiederhergestellt werden.
Im Status „Beendet“ kehrt die Aktivität entweder zurück, um mit dem Nutzer zu interagieren, oder sie wird beendet und verschwindet. Wenn die Aktivität zurückkehrt, ruft das System onRestart auf. Wenn Activity abgeschlossen ist, ruft das System onDestroy auf.
onDestroy
onDestroy wird aufgerufen, bevor die Aktivität beendet wird. Das System ruft diesen Callback aus einem von zwei Gründen auf:
- Die Aktivität wird beendet, weil der Nutzer sie vollständig schließt oder weil
finishfür die Aktivität aufgerufen wird. - Das System zerstört die Aktivität vorübergehend aufgrund einer Konfigurationsänderung, z. B. wenn das Gerät gedreht wird oder in den Mehrfenstermodus wechselt.
Wenn die Aktivität in den Status „Zerstört“ wechselt, empfängt jede lebenszyklusbewusste Komponente, die an den Lebenszyklus der Aktivität gebunden ist, das Ereignis ON_DESTROY. Hier können die Lebenszykluskomponenten alles bereinigen, was sie benötigen, bevor die Activity zerstört wird.
Anstatt Logik in Ihr Activity einzufügen, um zu ermitteln, warum es zerstört wird, verwenden Sie ein ViewModel-Objekt, das die relevanten Ansichtsdaten für Ihr Activity enthält. Wenn die Activity aufgrund einer Konfigurationsänderung neu erstellt wird, muss die ViewModel nichts tun, da sie beibehalten und an die nächste Activity-Instanz übergeben wird.
Wenn die Activity nicht neu erstellt wird, wird die Methode onCleared für die ViewModel aufgerufen, in der alle Daten bereinigt werden können, die vor dem Löschen erforderlich sind. Mit der Methode isFinishing können Sie zwischen diesen beiden Szenarien unterscheiden.
Wenn die Aktivität beendet wird, ist onDestroy der letzte Lebenszyklus-Callback, den die Aktivität empfängt. Wenn onDestroy als Ergebnis einer Konfigurationsänderung aufgerufen wird, erstellt das System sofort eine neue Aktivitätsinstanz und ruft dann onCreate für diese neue Instanz in der neuen Konfiguration auf.
Mit dem onDestroy-Callback werden alle Ressourcen freigegeben, die nicht von früheren Callbacks wie onStop freigegeben wurden.
Vorübergehenden UI-Status speichern und wiederherstellen
Nutzer erwarten, dass der UI-Zustand einer Aktivität während einer Konfigurationsänderung, z. B. einer Drehung oder dem Wechsel in den Mehrfenstermodus, gleich bleibt. Das System zerstört die Aktivität jedoch standardmäßig, wenn eine solche Konfigurationsänderung eintritt, wodurch der in der Aktivitätsinstanz gespeicherte UI-Status gelöscht wird.
Ebenso erwartet ein Nutzer, dass der UI-Status gleich bleibt, wenn er vorübergehend zu einer anderen App wechselt und später zu Ihrer App zurückkehrt. Das System kann den Prozess Ihrer Anwendung jedoch beenden, während der Nutzer nicht da ist und Ihre Aktivität beendet wird.
Wenn Systembeschränkungen die Aktivität beenden, bewahren Sie den temporären UI-Status des Nutzers mithilfe einer Kombination aus ViewModel, onSaveInstanceState und/oder lokalem Speicher. Weitere Informationen zu Nutzererwartungen im Vergleich zum Systemverhalten und dazu, wie Sie komplexe UI-Statusdaten bei systeminitiierten Aktivitäten und Prozessbeendigung am besten beibehalten, finden Sie unter UI-Status speichern.
In diesem Abschnitt wird beschrieben, was der Instanzstatus ist und wie Sie die Methode onSaveInstance implementieren, die ein Callback für die Aktivität selbst ist. Wenn Ihre UI-Daten nicht sehr umfangreich sind, können Sie onSaveInstance allein verwenden, um den UI-Status sowohl bei Konfigurationsänderungen als auch bei vom System initiierten Prozessbeendigungen beizubehalten. Da für onSaveInstance jedoch Serialisierungs-/Deserialisierungskosten anfallen, verwenden Sie in den meisten Fällen sowohl ViewModel als auch onSaveInstance, wie unter UI-Zustände speichern beschrieben.
Instanzstatus
Es gibt einige Szenarien, in denen Ihre Aktivität aufgrund des normalen App-Verhaltens beendet wird, z. B. wenn der Nutzer die Schaltfläche „Zurück“ drückt oder Ihre Aktivität durch Aufrufen der Methode finish ihr eigenes Beenden signalisiert.
Wenn Ihre Aktivität beendet wird, weil der Nutzer auf „Zurück“ drückt oder die Aktivität selbst beendet wird, ist sowohl das System als auch der Nutzer für immer von dieser Activity-Instanz getrennt. In diesen Szenarien entspricht die Erwartung des Nutzers dem Verhalten des Systems und Sie haben keinen zusätzlichen Aufwand.
Wenn das System die Aktivität jedoch aufgrund von Systembeschränkungen (z. B. einer Konfigurationsänderung oder Speichermangel) beendet, ist die tatsächliche Activity-Instanz zwar nicht mehr vorhanden, das System merkt sich aber, dass sie existiert hat. Wenn der Nutzer versucht, zur Aktivität zurückzukehren, erstellt das System eine neue Instanz dieser Aktivität mit einer Reihe von gespeicherten Daten, die den Zustand der Aktivität beschreiben, als sie beendet wurde.
Die gespeicherten Daten, die das System zum Wiederherstellen des vorherigen Zustands verwendet, werden als Instanzstatus bezeichnet. Es handelt sich um eine Sammlung von Schlüssel/Wert-Paaren, die in einem Bundle-Objekt gespeichert sind. Standardmäßig verwendet das System den Bundle-Instanzstatus, um Informationen zu jedem View-Objekt in Ihrem Aktivitätslayout zu speichern, z. B. den Textwert, der in ein EditText-Widget eingegeben wurde.
Wenn Ihre Aktivitätsinstanz also zerstört und neu erstellt wird, wird der Zustand des Layouts ohne Code von Ihnen wiederhergestellt. Ihre Aktivität enthält jedoch möglicherweise mehr Statusinformationen, die Sie wiederherstellen möchten, z. B. Mitgliedsvariablen, die den Fortschritt des Nutzers in der Aktivität erfassen.
Ein Bundle-Objekt ist nicht geeignet, um mehr als eine triviale Menge an Daten zu speichern, da es eine Serialisierung im Hauptthread erfordert und Arbeitsspeicher des Systemprozesses belegt. Wenn Sie mehr als eine sehr kleine Menge an Daten beibehalten möchten, sollten Sie einen kombinierten Ansatz verwenden, bei dem Sie persistenten lokalen Speicher, die Methode onSaveInstanceState und die Klasse ViewModel verwenden, wie unter UI-Zustände speichern beschrieben.
Einfachen, schlanken UI-Status mit onSaveInstanceState speichern
Wenn die Aktivität beendet wird, ruft das System die Methode onSaveInstanceState auf, damit deine Aktivität Statusinformationen in einem Instanzstatus-Bundle speichern kann. Bei der Standardimplementierung dieser Methode werden vorübergehende Informationen zum Status der View-Hierarchie der Aktivität gespeichert, z. B. der Text in einem EditText-Widget oder die Scrollposition eines ListView-Widgets.
Wenn Sie zusätzliche Informationen zum Instanzstatus für Ihre Aktivität speichern möchten, überschreiben Sie onSaveInstanceState und fügen Sie dem Bundle-Objekt Schlüssel/Wert-Paare hinzu, die gespeichert werden, falls Ihre Aktivität unerwartet beendet wird. Wenn Sie onSaveInstanceState überschreiben, müssen Sie die Implementierung der Superklasse aufrufen, damit die Standardimplementierung den Status der Ansichtshierarchie speichert.
Dies wird im folgenden Beispiel veranschaulicht:
Kotlin
override fun onSaveInstanceState(outState: Bundle?) {
// Save the user's current game state.
outState?.run {
putInt(STATE_SCORE, currentScore)
putInt(STATE_LEVEL, currentLevel)
}
// Always call the superclass so it can save the view hierarchy state.
super.onSaveInstanceState(outState)
}
companion object {
val STATE_SCORE = "playerScore"
val STATE_LEVEL = "playerLevel"
}
Java
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state.
savedInstanceState.putInt(STATE_SCORE, currentScore);
savedInstanceState.putInt(STATE_LEVEL, currentLevel);
// Always call the superclass so it can save the view hierarchy state.
super.onSaveInstanceState(savedInstanceState);
}
Wenn Sie persistente Daten wie Nutzereinstellungen oder Daten für eine Datenbank speichern möchten, sollten Sie dies tun, wenn Ihre Aktivität im Vordergrund ist. Wenn sich keine solche Möglichkeit ergibt, speichern Sie die persistenten Daten während der onStop-Methode.
UI-Status der Aktivität mithilfe des gespeicherten Instanzstatus wiederherstellen
Wenn Ihre Aktivität nach dem vorherigen Beenden neu erstellt wird, können Sie den gespeicherten Instanzstatus aus dem Bundle wiederherstellen, das das System an Ihre Aktivität übergibt. Sowohl die Callback-Methode onCreate als auch onRestoreInstanceState erhalten denselben Bundle, der die Informationen zum Instanzstatus enthält.
Da die Methode onCreate aufgerufen wird, unabhängig davon, ob das System eine neue Instanz Ihrer Aktivität erstellt oder eine vorherige neu erstellt, müssen Sie prüfen, ob der Status Bundle null ist, bevor Sie versuchen, ihn zu lesen. Wenn sie null ist, erstellt das System eine neue Instanz der Aktivität, anstatt eine zuvor zerstörte Instanz wiederherzustellen.
Das folgende Code-Snippet zeigt, wie Sie einige Statusdaten in onCreate wiederherstellen können:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // Always call the superclass first
// Check whether we're recreating a previously destroyed instance.
if (savedInstanceState != null) {
with(savedInstanceState) {
// Restore value of members from saved state.
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
} else {
// Probably initialize members with default values for a new instance.
}
// ...
}
Java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance.
if (savedInstanceState != null) {
// Restore value of members from saved state.
currentScore = savedInstanceState.getInt(STATE_SCORE);
currentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance.
}
// ...
}
Anstatt den Status während onCreate wiederherzustellen, können Sie onRestoreInstanceState implementieren, das vom System nach der Methode onStart aufgerufen wird. Das System ruft onRestoreInstanceState nur auf, wenn ein gespeicherter Status zum Wiederherstellen vorhanden ist. Sie müssen also nicht prüfen, ob Bundle null ist.
Kotlin
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
// Always call the superclass so it can restore the view hierarchy.
super.onRestoreInstanceState(savedInstanceState)
// Restore state members from saved instance.
savedInstanceState?.run {
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
}
Java
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy.
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance.
currentScore = savedInstanceState.getInt(STATE_SCORE);
currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
Zwischen Aktivitäten wechseln
Eine App ruft während ihres Lebenszyklus wahrscheinlich mehrmals eine Activity auf und beendet sie wieder, z. B. wenn der Nutzer auf den Button „Zurück“ des Geräts tippt oder die Activity eine andere Activity startet.
In diesem Abschnitt werden Themen behandelt, die Sie für die Implementierung erfolgreicher Aktivitätsübergänge benötigen. Dazu gehören das Starten einer Aktivität aus einer anderen Aktivität, das Speichern des Aktivitätsstatus und das Wiederherstellen des Aktivitätsstatus.
Eine Aktivität über eine andere starten
Eine Aktivität muss oft irgendwann eine andere Aktivität starten. Dies ist beispielsweise erforderlich, wenn eine App vom aktuellen Bildschirm zu einem neuen wechseln muss.
Je nachdem, ob Ihre Aktivität ein Ergebnis von der neuen Aktivität zurückerhalten soll, die sie starten möchte, starten Sie die neue Aktivität entweder mit der Methode startActivity oder mit der Methode startActivityForResult. In beiden Fällen übergeben Sie ein Intent-Objekt.
Das Intent-Objekt gibt entweder die genaue Aktivität an, die Sie starten möchten, oder beschreibt die Art der Aktion, die Sie ausführen möchten. Das System wählt die passende Aktivität für Sie aus, die auch aus einer anderen Anwendung stammen kann. Ein Intent-Objekt kann auch kleine Datenmengen enthalten, die von der gestarteten Aktivität verwendet werden. Weitere Informationen zur Klasse Intent finden Sie unter Intents und Intent-Filter.
startActivity
Wenn die neu gestartete Aktivität kein Ergebnis zurückgeben muss, kann die aktuelle Aktivität sie durch Aufrufen der Methode startActivity starten.
Wenn Sie in Ihrer eigenen Anwendung arbeiten, müssen Sie häufig nur eine bekannte Aktivität starten. Das folgende Code-Snippet zeigt beispielsweise, wie eine Aktivität namens SignInActivity gestartet wird.
Kotlin
val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)
Java
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
Ihre App möchte möglicherweise auch eine Aktion ausführen, z. B. eine E‑Mail, SMS oder Statusaktualisierung senden, und dabei Daten aus Ihren Aktivitäten verwenden. In diesem Fall hat Ihre Anwendung möglicherweise keine eigenen Aktivitäten, um solche Aktionen auszuführen. Sie können stattdessen die Aktivitäten anderer Anwendungen auf dem Gerät nutzen, die die Aktionen für Sie ausführen können.
Hier sind Intents wirklich wertvoll. Sie können einen Intent erstellen, der eine Aktion beschreibt, die Sie ausführen möchten, und das System startet die entsprechende Aktivität aus einer anderen Anwendung. Wenn es mehrere Aktivitäten gibt, die den Intent verarbeiten können, kann der Nutzer auswählen, welche verwendet werden soll. Wenn Sie dem Nutzer beispielsweise ermöglichen möchten, eine E‑Mail-Nachricht zu senden, können Sie den folgenden Intent erstellen:
Kotlin
val intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)
Java
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
Das dem Intent hinzugefügte Extra EXTRA_EMAIL ist ein String-Array von E-Mail-Adressen, an die die E-Mail gesendet werden soll. Wenn eine E‑Mail-Anwendung auf diese Absicht reagiert, liest sie das im Extra bereitgestellte String-Array und fügt die Adressen in das Feld „An“ des E‑Mail-Erstellungsformulars ein. In diesem Fall wird die Aktivität der E‑Mail-Anwendung gestartet und Ihre Aktivität wird fortgesetzt, wenn der Nutzer fertig ist.
startActivityForResult
Manchmal möchten Sie nach dem Ende einer Aktivität ein Ergebnis erhalten. Sie können beispielsweise eine Aktivität starten, mit der der Nutzer eine Person in einer Kontaktliste auswählen kann. Am Ende wird die ausgewählte Person zurückgegeben. Rufen Sie dazu die Methode startActivityForResult(Intent, int) auf. Der ganzzahlige Parameter identifiziert den Aufruf.
Mit dieser Kennung soll zwischen mehreren Aufrufen von startActivityForResult(Intent, int) aus derselben Aktivität unterschieden werden. Es handelt sich nicht um einen globalen Identifier und es besteht keine Gefahr, dass er mit anderen Apps oder Aktivitäten in Konflikt gerät. Das Ergebnis wird über die Methode onActivityResult(int, int, Intent) zurückgegeben.
Wenn eine untergeordnete Aktivität beendet wird, kann sie setResult(int) aufrufen, um Daten an die übergeordnete Aktivität zurückzugeben. Die untergeordnete Aktivität muss einen Ergebniscode liefern, der die Standardergebnisse RESULT_CANCELED, RESULT_OK oder benutzerdefinierte Werte ab RESULT_FIRST_USER sein kann.
Außerdem kann die untergeordnete Aktivität optional ein Intent-Objekt mit allen gewünschten zusätzlichen Daten zurückgeben. Die übergeordnete Aktivität verwendet die Methode onActivityResult(int, int, Intent) zusammen mit der Ganzzahl-ID, die ursprünglich von der übergeordneten Aktivität bereitgestellt wurde, um die Informationen zu empfangen.
Wenn eine untergeordnete Aktivität aus irgendeinem Grund fehlschlägt, z. B. abstürzt, erhält die übergeordnete Aktivität ein Ergebnis mit dem Code RESULT_CANCELED.
Kotlin
class MyActivity : Activity() {
// ...
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// When the user center presses, let them pick a contact.
startActivityForResult(
Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
PICK_CONTACT_REQUEST)
return true
}
return false
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
when (requestCode) {
PICK_CONTACT_REQUEST ->
if (resultCode == RESULT_OK) {
// A contact was picked. Display it to the user.
startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
}
}
}
companion object {
internal val PICK_CONTACT_REQUEST = 0
}
}
Java
public class MyActivity extends Activity {
// ...
static final int PICK_CONTACT_REQUEST = 0;
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// When the user center presses, let them pick a contact.
startActivityForResult(
new Intent(Intent.ACTION_PICK,
new Uri("content://contacts")),
PICK_CONTACT_REQUEST);
return true;
}
return false;
}
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == PICK_CONTACT_REQUEST) {
if (resultCode == RESULT_OK) {
// A contact was picked. Display it to the user.
startActivity(new Intent(Intent.ACTION_VIEW, data));
}
}
}
}
Aktivitäten koordinieren
Wenn eine Aktivität eine andere startet, durchlaufen beide Lebenszyklusübergänge. Die erste Aktivität wird beendet und wechselt in den Status „Pausiert“ oder „Beendet“, während die andere Aktivität erstellt wird. Wenn diese Aktivitäten Daten gemeinsam nutzen, die auf der Festplatte oder an einem anderen Ort gespeichert sind, ist es wichtig zu wissen, dass die erste Aktivität nicht vollständig beendet wird, bevor die zweite erstellt wird. Vielmehr überschneidet sich der Prozess des Startens des zweiten mit dem Prozess des Beendens des ersten.
Die Reihenfolge der Lebenszyklus-Callbacks ist genau definiert, insbesondere wenn sich die beiden Aktivitäten im selben Prozess befinden, d. h. in derselben App, und eine die andere startet. So läuft es ab, wenn Aktivität A Aktivität B startet:
- Die Methode
onPausevon Aktivität A wird ausgeführt. - Die Methoden
onCreate,onStartundonResumevon Aktivität B werden nacheinander ausgeführt. Aktivität B ist jetzt im Fokus des Nutzers. - Wenn Aktivität A nicht mehr auf dem Bildschirm zu sehen ist, wird die Methode
onStopausgeführt.
Mit dieser Sequenz von Lebenszyklus-Callbacks können Sie den Übergang von Informationen von einer Aktivität zur nächsten verwalten.