Android_Tutorial_Lektion27_fotolia_RA_Studio_46292813

Programmier Tutorial: Apps für Android entwickeln – Teil 27: Der Lebenszyklus einer Android App (Android Activity Lifecycle)

In den nächsten drei Lektionen werden wir uns mit dem Android Activity Lifecycle, dem Lebenszyklus von Android Anwendungen, beschäftigen. Dabei werden wir die verschieden Stufen beschreiben, die eine Android App während ihres Lebens durchschreitet.

Da dieses spannende Thema für die Entwicklung komplexer Android Apps von zentraler Bedeutung ist, werden wir es im theoretischen Teil dieser Lektion mit besonderer Sorgfalt behandeln.


Dabei werden wir erfahren in welchen Zuständen eine Activity in Android existieren und über welche Lifecycle-Methode sie die Zustände wechseln kann. Die verschieden Lifecycle-Methode werden wir anschließend in der MainActivity-Klasse unserer Android App implementieren und von ihnen kurze Log-Meldungen ausgeben lassen.

Auf diese Weise können wir uns die einzelnen Lebensphasen unserer Activity direkt im Logcat Tool Window anzeigen lassen und somit die internen Vorgänge besser nachvollziehen.

Abschließend werden wir unsere Android App im Emulator auf einem Android Virtual Device ausführen und anhand der Log-Meldungen überprüfen, welche Zustände unsere Activity durchläuft und wann welche Lifecycle-Methoden zur Zustandsänderung vom Android System aufgerufen werden.

1. Der Lebenszyklus einer Activity in Android

Die Activity-Klasse ist eine sehr bedeutende Komponenten von Android Apps. Eine Aktivität stellt das Fenster bereit, in welchem die Anwendung ihre Benutzeroberfläche zeichnet und mit welchem der Benutzer interagiert. Dieses Fenster füllt normalerweise den Bildschirm, kann aber auch kleiner sein und über anderen Fenstern schweben.

Eine Android Anwendung besteht meist aus mehreren Activities, die lose miteinander verbunden sind. Jede Activity kann eine andere Activity starten, dabei wird die aktuelle Activity gestoppt und die gestartete Activity kommt in den Fokus. Der Zustand der gestoppten Aktivität bleibt dabei im Android System erhalten.

Die Art und Weise, wie Activities gestartet und zusammengesetzt werden, ist ein wesentlicher Bestandteil des Android Systems. Im Gegensatz zu normalen Computerprogrammen, die mit einer main() Methode gestartet werden, werden Activities vom Android System mit Hilfe mehrerer spezieller Callback-Methoden (Rückrufmethoden) stufenweise instanziiert.

Diese speziellen Callback-Methode werden zu bestimmten Lebensphasen der Activity vom Android System aufgerufen. Daher werden sie auch Lifecycle Callbacks genannt. Wenn bspw. eine Activity gestoppt wird, weil eine neue Activity startet, wird sie über die Zustandsänderung durch die Lifecycle Callbacks informiert.

In Android sind mehrere Callback-Methoden implementiert, die bei einer Zustandsänderung der Aktivität aufgerufen werden. Jede Callback-Methode bietet die Gelegenheit bestimmte, notwendige Arbeiten auszuführen, bevor die Zustandsänderung in Kraft tritt. Welche Callback-Methode vom Android System aufgerufen wird. ist vom Zustand abhängig, in welchem die Activity gerade befindet.

Wir werden uns nun genauer ansehen, in welchen Zuständen eine Activity in Android existieren kann.

1.1 In diesen drei Zuständen kann eine Activity in Android existieren

Der Lifecycle einer Activity wird von anderen Activities, dem eigenen Task und dem Back Stack, einem Stapel der die genutzten Activities verwaltet, direkt beeinflusst. Durch Implementieren der Lifecycle Callbacks kann der Lebenszyklus der eigenen Activities verwaltet werden.

Für das Entwickeln komplexer und flexibler Android Anwendungen ist es von größter Bedeutung, diese Callbacks richtig zu implementieren. Damit dies gelingt, sind genaue Kenntnisse über die Zustände, in denen eine Activity existieren kann, zwingend erforderlich.

Eine Activity kann in den folgenden drei Zuständen existieren:

Resumed State
Immer wenn eine Activity im Bildschirmvordergrund angezeigt wird und den Benutzer-Fokus besitzt, befindet sie sich Resumed-Zustand. In diesem Zustand kann die App mit dem Benutzer interagieren. Rechenintensive und kritische Anwendungsprozesse, wie Animationen oder Datenbankzugriffe, sollten im Resume State erfolgen.

Die Activity bleibt in diesem Zustand, bis ein Ereignis eintritt, das den Fokus von der Activity nimmt. Ein solches Ereignis kann bspw. sein, dass der Benutzer zu einer anderen Activity navigiert.

Wenn ein unterbrechendes Ereignis auftritt, wechselt die Activity in den Paused-Zustand, und das Android System ruft den onPause() Callback auf. Wird die Activity aus dem Paused-Zustand wieder fortgesetzt, ruft das Android System erneut die onResume() Methode auf und die Activity betritt wieder den Resumed-Zustand. Aus diesem Grund sollten im onResume() Callback die Komponenten initialisiert werden, welche im onPause() Callback freigegeben werden.



Paused State
Durch bestimmte Ereignisse kann die Ausführung einer Activity unterbrochen werden. Dies ist bspw. der Fall, wenn eine andere Activity in den Vordergrund rückt und die ausgeführte Activity teilweise überlagert. In einer solchen Situation wird die onPause() Methode vom Android System aufgerufen und die ausgeführte Activity geht vom Resumed– in den Paused-Zustand über.

Im Paused-Zustand ist eine Activity noch vollständig intakt (alive). Die Instanz der Activity wird weiterhin im Speicher gehalten und alle Zustands- und Memberinformationen bleiben erhalten. Die pausierte Activity kann jedoch vom Android System in Situationen mit extrem niedrigem Speicher zerstört werden.

Nachdem die Ausführung der onPause() Methode abgeschlossen wurde, verweilt die Activity im Paused State, bis sie entweder wieder in den Resumed-Zustand zurückkehrt oder komplett von einer anderen Activity überlagert wird, also für den Benutzer nicht mehr sichtbar ist.

Falls die Activity wieder fortgesetzt werden soll, ruft das Android System die onResume() Methode auf. Die Activity kehrt daraufhin vom Paused– in den Resumed-Zustand zurück. Da die Instanz der Activity noch völlig intakt im Speicher lag, gehen bei diesem Übergang keine Informationen verloren und ihre Komponenten müssen nicht erneut initialisiert werden. Falls die Activity komplett unsichtbar für den Benutzer wird, ruft das Android System die onStop() Methode auf und die Activity geht in den Stopped State über.

In Situationen mit extrem niedrigem Speicher kann es vorkommen, dass das Android System eine pausierte Activity beendet und anschließend zerstört. Dies geschieht entweder durch Aufrufen der finish() Methode oder durch direktes Beenden ihres Prozesses. Es ist zwar unwahrscheinlich, dass eine pausierte Activity gewaltsam beendet wird, sollte jedoch vom Entwickler einkalkuliert werden.



Stopped State
Wenn die Activity für den Benutzer nicht mehr sichtbar ist, betritt sie den Stopped-Zustand und das Android System ruft die onStop() Methode auf. Dies kann auftreten wenn eine andere Activity gestartet wird und vollständig in den Bildschirmvordergrund rückt oder wenn die ausgeführte Activity ihre Aufgaben erfüllt hat und beendet wird.

Wenn eine Activity den Stopped State betritt, bleibt die Instanz der Activity weiterhin im Speicher bestehen. Eine gestoppte Activity bleibt vollständig intakt. Das gesamt Activity-Objekt wird im Speicher gehalten und alle Zustands- und Memberinformationen bleiben erhalten. Die Activity ist jedoch nicht mehr dem Window Manager zugewiesen.

Wird die gestoppte Activity wieder fortgesetzt, müssen ihre Komponenten nicht erneut initialisiert werden. Das Android System speichert den aktuellen Zustand jedes View-Objekts im Layout der Activity. So bleibt bspw. die Scroll-Position eines ListViews erhalten, an die der Benutzer vor dem Betreten des Stopped-Zustands navigiert hatte.

Von dem Stopped State kann die Activity entweder zurück in den Resumed State kehren, dann wird die onRestart() Methode vom Android System aufgerufen, oder die Activity schließt ihre Berechnungen ab und wird beendet, dann ruft das Android System die onDestroy() Methode auf. In Situationen mit extrem wenig verfügbarem Speicher kann eine gestoppte Activity vom Android System zerstört werden, ohne dass sie ihre Berechnungen abschließen konnte.



Somit bleibt festzuhalten, dass eine pausierte oder gestoppte Activity jederzeit vom Android System zerstört werden kann. Dies geschieht entweder durch Aufrufen der finish() Methode oder durch direktes Beenden ihres Prozesses. Wird eine zerstörte Activity wieder geöffnet, muss sie von ganz vorne wieder neu erstellt werden.

Wir haben nun die drei Zustände kennengelernt, in welchen eine Activity in Android existieren kann. Als Nächstes werden wir den gesamten Lebenszyklus einer Activity betrachten und dabei die verschiedenen Lifecycle-Methode kennenlernen, mit deren Hilfe eine Activity in ihren jeweiligen Zustand überführt wird.

1.2 Der Lebenszyklus einer Activity mit seinen Lifecycle-Methoden

Wenn eine Activity einen Zustand verlässt und einen neuen Zustand betritt, wird sie über verschiedene Callback-Methoden über die Zustandsänderung informiert. Alle Callback-Methoden können überschrieben werden.

Auf diese Weise kann auf die Zustandsänderung entsprechend reagiert und die jeweils notwendige Arbeit ausgeführt werden. Um zu wissen welche Arbeit in welcher Callback-Methode durchgeführt werden muss, ist eine genaue Kenntnis der Lifecycle Callbacks erforderlich.

In Android sind die folgenden Lifecycle Callbacks definiert:

  • onCreate(Bundle savedInstanceState) – Die Activity wird erstellt. Hier beginnt der Lebenszyklus.
  • onStart() – Die Activity ist kurz davor sichtbar zu werden.
  • onResume() – Die Activity ist sichtbar geworden und hat den Benutzer-Fokus.
  • onPause() – Eine andere Activity erhält den Fokus. Diese Activity wird pausiert.
  • onStop() – Die Activity ist nicht mehr sichtbar und wird nun gestoppt.
  • onRestart() – Die Activity wird wiederaufgenommen, nachdem sie gestoppt war. Als Nächstes wird onStart() aufgerufen.
  • onDestroy() – Die Activity wird zerstört werden. Hier endet der Lebenszyklus.

Neben diesen sieben Lifecycle Callback Methoden, die im Leben einer Activity immer aufgerufen werden, existieren noch zwei optionale Callback-Methoden, die für das Speichern des Activity-Zustands zuständig sind, wenn die Activity vom Android System gewaltsam beendet werden muss. Dies kann der Fall sein, wenn zu wenig Speicher vorhanden ist oder sich die Bildschirmausrichtung von Landscape zu Portrait ändert.

Mit diesen beiden optionalen Lifecycle Callbacks kann der Zustand einer zerstörten Activity gehalten werden:

  • onSaveInstanceState(Bundle outState) – Die Activity wird in den nächsten Momenten gestoppt. Vorher kann ihr aktueller Zustand in einem Bundle-Objekt als Sammlung von Schlüssel-Wert Paaren (Key-Value pairs) gespeichert werden.

    Die onSaveInstanceState() Methode wird aber nur vom Android System aufgerufen, wenn die Activity zerstört werden soll und das Android System den Zustand der Activity halten will. Dies ist nicht der Fall, wenn der Benutzer die App durch Klicken des Back-Buttons bewusst beendet.

    Wenn die onSaveInstanceState() Methode aufgerufen wurde, wird eine Bundle-Objekt erzeugt, in das wichtige Informationen über den Zustand der Activity als Sammlung von Schlüssel-Wert Paaren abgelegt werden können. Beim Neuerstellen der dann zerstörten Activity können die so gespeicherten Zustandsinformationen in den beiden Methode onCreate() und onRestoreInstanceState() für das Erzeugen der Activity genutzt werden.

    Wird die onSaveInstanceState() Methode vom Android System aufgerufen, erfolgt dies nach onStop() ab Android 9.0 (Pie). Für Android 8.0 (Oreo) und früher erfolgt der Aufruf vor onStop() und kann sogar vor onPause() erfolgen, wobei dies nicht exakt festgelegt ist. Es wird nur garantiert, dass der Aufruf bis Android 8.0 vor onStop() stattfinden wird.

  • onRestoreInstanceState(Bundle savedInstanceState) – Die Activity wird wieder hergestellt, nachdem sie bspw. aufgrund von Speichermangel oder dem Wechsel der Bildschirmausrichtung vom Android System zerstört wurde. Dieser Callback wird nur aufgerufen, wenn das Bundle-Objekt vorhanden, also nicht null, ist. Der Aufruf erfolgt unmittelbar nach onStart().

    Es ist möglich den Zustand einer zerstörten Activity sowohl in der onRestoreInstanceState() als auch in der onCreate() Methode wiederherzustellen. Beide Methode erhalten jeweils beim Aufruf vom Android System das Bundle-Objekt übergeben. Der Entwickler muss daher gut überlegen, von welcher dieser beiden Methode er welche Komponenten der Activity wiederherstellen lässt.

Die folgende Abbildung verdeutlicht in welcher Reihenfolge die Lifecycle Callbacks aufgerufen werden:

android_activity_lifecycle_new

Die Callback-Methoden des Activity Lifecycles in Android

In der oberen Grafik repräsentiert jedes Rechteck eine Callback-Methoden, die von uns implementiert werden kann, um mit ihrer Hilfe die notwendigen Operationen bei Zustandsänderungen der Activity durchzuführen.

Die beiden Callback-Methoden onSaveInstanceState() und onRestoreInstanceState() werden nur in bestimmten Situationen vom Android System aufgerufen. Wir werden in der nächsten Lektion über das Zwischenspeichern von des Activity-Zustands zur Laufzeit näher auf sie eingehen.

Hinweis: Wird eine dieser Lifecycle-Methoden implementiert, muss unbedingt als Erstes die Implementierung der Basisklasse aufgerufen werden, bevor der eigene Code beginnt. In der onPause() Callback-Methode wäre dies dann das Aufrufen der Implementierung der Superklasse mit super.onPause(); gleich am Anfang des Methodenrumpfs.

Alle Callback-Methoden zusammengenommen ergeben den kompletten Lebenszyklus einer Activity in Android. Der Zyklus kann mehrfach durchlaufen werden.

Betrachtet man den Lebenszyklus im Detail, können die folgenden drei verschachtelten Schleifen erkannt werden:

  • Die Gesamte Lebenszeit einer Activity findet zwischen dem Aufruf der onCreate() und onDestroy() Methoden statt. Eine Activity sollte die grundlegenden Initialisierungen in der onCreate() Methode vornehmen und alle verbleibenden Ressourcen in der onDestroy() Methode wieder freigeben.

  • Die Sichtbare Lebenszeit einer Activity findet zwischen dem Aufruf der onStart() und onStop() Methoden statt. Während dieser Zeit kann der Benutzer die Activity auf dem Bildschirm sehen und mit ihr interagieren. Sie kann aber zeitweise von einer anderen Activity zum Teil verdeckt sein, sie ist dann noch sichtbar im Hintergrund, befindet sich aber im Paused State.

  • Die Vordergrund Lebenszeit einer Activity in Android findet zwischen dem Aufruf der onResume() und onPause() Methoden statt. Während dieser Zeit befindet sich die Activity im Bildschirmvordergrund über allen anderen Activities und besitzt den Benutzer-Fokus. Eine Activity kann sehr oft in diesen Zustand gehen und diesen wieder verlassen.

Hinweis: Bspw. wird die onPause() Methode aufgerufen, wenn das Android Gerät in den Schlafmodus geht oder wenn ein Dialog erscheint. Da diese Zustandsänderung vom Resumed– zum Pauses-Zustand und wieder zurück oft stattfindet, sollte der Code in den beiden Methoden onResume() und onPause() sehr schnell ausführbar sein (lightweight), um langsame Übergänge zu vermeiden.

Wir haben nun den Activity Lifecycle von Android mit seinen Callback-Methoden näher kennengelernt. Dabei haben wir erfahren mit Hilfe welcher Methoden eine Activity in Android ihren Zustand wechselt. Im folgenden Abschnitt werden wir uns jeden einzelnen Lifecycle-Callback noch einmal genauer ansehen und beschreiben welches seine jeweiligen Aufgaben sind.

1.3 Die Lifecycle-Methoden einer Activity im Detail

In der unteren Aufstellung ist jede Callback-Methode des Android Activity Lifecycles nochmals aufgeführt. Für jede Methode wird detailliert beschrieben, wofür sie verantwortlich ist und welche Methode nach ihr vom Android System aufgerufen wird. Zudem wird angegeben, ob der Prozess der App vom Android System beendet werden kann, nachdem die entsprechende Callback-Methode abgearbeitet wurde.

onCreate()
Die onCreate() Callback-Methode wird aufgerufen, wenn die Activity das erste Mal erzeugt wird. Sie muss von uns zwingend implementiert werden. In ihr sollten alle grundlegenden Initialisierungsarbeiten vorgenommen werden, die nur einmal im gesamten Leben der Activity stattfinden. Diese Arbeiten können sein, Erzeugen von Views, Registrieren von Datenquellen für Listen, Initialisieren von Hintergrund-Threads und Instanziieren vom Membervariablen.

Außerdem wird dieser Methode ein Bundle-Objekt übergeben, welches den vorherigen Zustand der Activity enthält, falls dieser Zustand vom Android System festgehalten wurde bzw. falls die Activity bereits einmal existierte. Im Anschluss an die onCreate() Methode wird immer die onStart() Methode vom Android System aufgerufen.

Nach der onCreate() Methode kann das Android System den App-Prozess noch nicht beenden.



onStart()
Das Android System ruft die onStart() Methode auf, um die Activity für den Benutzer sichtbar zu machen. Sie bereitet die Activity darauf vor in den Bildschirmvordergrund zu rücken und interaktiv zu werden. In ihr sollten die Komponenten initialisiert werden, die für das Verwalten der Benutzeroberfläche der Activity verantwortlich sind.

Die Anweisungen in der onStart() Methode sollte schnell abgeschlossen werden können, da die Activity sie auf dem Weg zum Resumed State nur durchläuft, ohne lange darin verweilen zu dürfen. Sobald die onStart() beendet wurde, betritt die Activity den Resumed-Zustand und das Android System ruft die onResume() Methode auf.

Nach der onStart() Methode kann das Android System den App-Prozess noch nicht beenden.



onResume()
Wenn die Activity in den Bildschirmvordergrund rückt, ruft das Android System die onResume() Methode auf. Die Activity ist dann im Resumed State und kann mit dem Benutzer interagieren. Sie bleibt solange in diesem Zustand, bis ein Ereignis eintritt, welches den Benutzer-Fokus von ihr nimmt. Ein solches unterbrechendes Ereignis kann bspw. ein eingehender Anruf oder das Navigieren zu einer anderen Activity sein.

Sobald ein solches unterbrechendes Ereignis eintritt, ruft das Android System die onPause() Methode auf, welche die Activity in den Paused State überführt. Falls die Activity dann wieder in dem Resumed-Zustand zurückkehrt, wird erneut die onResume() Methode aufgerufen. Aus diesem Grund sollten in der onResume() Methode alle Komponenten wieder initialisiert werden, die in der onPause() Methode freigegeben wurden.

Nach der onResume() Methode kann das Android System den App-Prozess noch nicht beenden.



onPause()
Das Android System ruft die onPause() Methode auf, sobald es erkennt, dass die Activity den Benutzer-Fokus verlieren wird. Es gibt mehrere Ereignisse, die zum Verlust des Benutzer-Fokus führen können und somit zum Aufruf der onPause() Methode:

  • Unterbrechende Ereignisse wie ein eingehender Anruf oder das Navigieren zu einer anderen Activity führen zu einem Pausieren der ausgeführten Activity. Dies ist der häufigste Fall.

  • Ab Android 7.0 können mehrer Apps im multi-window mode gleichzeitig ausgeführt werden. Da immer nur die Activity der aktiven App den Benutzer-Fokus besitzen kann, werden die Activities der anderen passiven Apps solange pausiert.

  • Eine neue halb-transparente Activity, wie ein Dialog, rückt in den Vordergrund und verdeckt die ausgeführte Activity teilweise. Solange die Activity aber noch sichtbar ist, jedoch keinen Benutzer-Fokus mehr besitzt, bleibt sie im Paused State.

Das Abschließen der onPause() Methode bedeutet nicht, dass die Activity den Paused-Zustand verlässt. Stattdessen verweilt die Activity solange im pausierten Zustand bis sie wieder fortgesetzt wird oder für den Benutzer nicht mehr sichtbar ist.

Falls die Activity wieder fortgesetzt wird, ruft das Android System die onResume() Methode auf und sie kehrt in den Resumed State zurück. Dabei bleibt der Zustand der Activity stets im Speicher erhalten und vollständig intakt. In diesem Szenario müssen die Komponenten der Activity nicht erneut initialisiert werden, die in den Methoden onCreate() und onStart() auf dem Weg zum Resumed State erzeugt wurden.

Falls die Activity für den Benutzer nicht mehr sichtbar ist und komplett verdeckt wird, ruft das Android System die onStop() Methode auf.

In der onPause() Methode sollten Animationen gestoppt und im Paused-Zustand nicht mehr benötigte System Ressourcen freigegeben werden. Diese Vorhaben sollten unbedingt sehr schnell ausführbar sein, da die nächste Activity erst danach fortgesetzt werden kann. Es sollten daher keine rechen- und zeitintensiven Operationen in ihr durchgeführt werden, wie Speichern der Benutzerdaten oder Tätigen von Netzwerk- bzw. Datenbankzugriffen. Solche Aufgaben sollten stattdessen in der onStop() Methode oder besser im Resume State, sofern möglich, durchgeführt werden.

Nach der onPause() Methode kann das Android System den App-Prozess direkt beenden, sollte dies aufgrund von Speichermangel erforderlich sein.



onStop()
Sobald die Activity für den Benutzer nicht mehr sichtbar ist, ruft das Android System die onStop() Methode auf und die Activity betritt den Stopped State. Dies kann passieren, wenn eine neu gestartete Activity den Bildschirm komplett bedeckt. Das Android System kann die onStop() Methode aber auch aufrufen, wenn die Activity ihre Ausführung durch Aufruf von finish() beendet hat und zerstört werden soll.

Wenn die Activity den Stopped State betreten hat, bleibt die Instanz der Activity im Speicher intakt. Ihre Zustands- und Memberinformationen bleiben erhalten, jedoch ist sie dem Window Manager nicht mehr zugewiesen. Wenn die Activity erneut fortgesetzt wird, müssen ihre Komponenten nicht nochmals initialisiert werden, die in den Methoden onCreate() und onStart() auf dem Weg zum Resumed State erzeugt wurden. Das Android System speichert auch den Zustand jedes View-Objekts im Layout der Activity, so dass bspw. die Scroll-Position eines ListViews erhalten bleibt.

Vom Stopped State kann die Activity entweder wieder fortgesetzt oder beendet werden. Soll die Activity wieder fortgesetzt werden, ruft das Android System die onRestart() Methode auf. Diese ist der Wiederaufnahme-Callback der Activity und führt anschließend zum Aufruf der onStart() Methode und danach in den Resumed State.

Hat die Activity ihre Ausführungen beendet und soll endgültig geschlossen werden, ruft das Android System die onDestroy() Methode auf, die zum Zerstören der Activity führt. In diesem Fall werden keine Zustandsinformationen über die Activity vom Android System aufrecht gehalten. Der Zustand der Activity geht vollständig verloren, das das Android System annimmt, dass der Benutzer die Activity nicht weiter benötigt.

In der onStop() Methode sollten alle System Ressource wieder freigegeben werden, die nicht mehr benötigt werden, solange sich die Activity im Stopped State befindet. Wurde bspw. in der onStart() Methode ein BroadcastReceiver registriert, der Änderungen der Benutzeroberfläche überwacht, kann dieser nun in der onStop() Methode wieder freigegeben werden, da die Benutzeroberfläche der Activity für den Benutzer nicht mehr sichtbar ist.

Hinweis: Nach der onStop() Methode kann das Android System den App-Prozess direkt beenden, sollte dies aufgrund von Speichermangel erforderlich sein. Wird die Activity im Stopped State zerstört, hält das Android System den Zustand ihrer View-Objekte (wie den Text in einem EditText-Widget oder die Scroll-Position eines ListViews) in einem Bundle-Objekt aufrecht. Sollte der Benutzer später wieder zur Activity zurückkehren, werden alle Zustände der View-Objekte mit Hilfe des Bundle-Objekt wiederhergestellt.

In der onStop() Methode können sogar relativ CPU-intensive Aufgaben, die für das Beenden der Activity notwendig sind, ausgeführt werden. Dies sollte aber nur hier geschehen, falls es nicht möglich ist die entsprechende Aufgabe im Resumed State der Activity durchzuführen.



onRestart()
Das Android System ruft die onRestart() Methode auf, wenn die gestoppte Activity wieder sichtbar werden soll. Sie ist der Wiederaufnahme-Callback und führt die Activity vom Stopped State in den Resumed State. Ihr folgen immer die onStart() und danach die onResume() Methoden.

Nach der onRestart() Methode kann das Android System den App-Prozess nicht beenden.



onDestroy()
Das Android System ruft die onDestroy() Methode auf, kurz bevor die Activity zerstört wird. Dies ist der letzte Callback-Aufruf den eine Activity erhält. Entweder wird die Activity gerade planmäßig mit der Methode finish() beendet oder das Android System zerstört den Prozess, in welchem die Activity ausgeführt wird, um Speicher freizugeben. Mit der Methode isFinishing() kann überprüft werden, welches von beiden Szenarien der Fall ist.

Das Android System kann aber auch die onDestroy() Methode aufrufen, wenn eine Änderung der Bildschirmorientierung auftritt. In diesem Fall wird umgehend nach onDestroy() die onCreate() Methode aufgerufen und alle Komponenten der Activity in der veränderten Orientierung neu erzeugt.

Die onDestroy() Methode gibt alle Ressourcen, die noch nicht in der onPause() und onStop() Methode freigegeben wurden, wieder frei. Ihr folgt kein weiterer Aufruf einer Callback-Methode. Die Activity endet hier permanent.



Wie den Beschreibungen der Callback-Methoden zu entnehmen ist, kann der Prozess, in dem eine Activity ausgeführt wird, nur nach den drei Methoden onPause(), onStop() und onDestroy() beendet werden (process killed). Vor der onPause() Methode kann eine Activity nicht vom Android System beendet werden.

Somit kann eine Activity im schlimmsten Fall direkt nach der onPause() Methode geschlossen werden. Sie ist die letzte Methode, die garantiert aufgerufen wird, bevor das System den Prozess, in dem die Activity ausgeführt wird, direkt aufgrund von Speichermangel beenden kann. Die Methoden onStop() und onDestroy() werden in jenem Fall nicht mehr aufgerufen.

Daher sollten bis zur onPause() Methode die kritischen Daten persistent gespeichert werden. Dies sollte aber entweder sehr schnell in der onPause() Methode ausgeführt werden oder zu einem vorherigen Zeitpunkt wenn sich die Activity noch im Bildschirmvordergrund befindet. Denn der Übergang in die nächste Activity kann erst nach Abschließen der onPause() Methode erfolgen.

Von allen Lifecycle Callback Methoden muss nur die onCreate() Methode zwingend von uns implementiert werden. Die anderen Callback-Methoden können optional je nach Komplexität der Android App ausprogrammiert werden. Auch wenn man nicht alle Lifecycle Callbacks für die eigene App benötigt, ist es dennoch wichtig, jede einzelne Callback-Methode und ihr jeweiliges Aufgabengebiet genau zu kennen.

Nachdem wir uns nun im theoretisch Teil ausgiebig mit dem Android Activity Lifecycle und seinen Callback-Methoden beschäftigt haben, ist es nun an der Zeit, das Erlernte in die Praxis umsetzen. Dazu werden wir im nächsten Abschnitt die vorgestellten Callback-Methoden in der MainActivity-Klasse unserer Android App implementieren.

Dabei werden wir die Callback-Methoden so implementieren, dass sie jeweils eine kurze Log-Meldung an die Konsole ausgeben. Auf diese Weise können wir uns die einzelnen Lebensphasen unserer Activity direkt im Logcat Tool Window von Android Studio anzeigen lassen und somit die internen Vorgänge besser nachvollziehen.

2. Implementieren der Lifecycle-Methoden in der MainActivity

Wir werden nun die Callback-Methoden des Android Activity Lifecycles in der MainActivity-Klasse unserer Android App implementieren. Bisher wird nur die onCreate() Methode von unserer Activity implementiert, so dass wir die anderen Callback-Methoden unserer Klasse noch hinzufügen müssen.

In dem unteren Quellcode sind die einzufügenden Lifecycle Callback Methode beispielhaft aufgeführt:

...

public static final String OUTER_TAG = MainActivity.class.getSimpleName();

...

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.v(OUTER_TAG, "1. Stufe: onCreate() betreten");

    setContentView(R.layout.activity_main);

    ...    
}

protected void onStart() {
    super.onStart();
    Log.v(OUTER_TAG, "2. Stufe: onStart() betreten");
}

protected void onResume() {
    super.onResume();
    Log.v(OUTER_TAG, "3. Stufe: onResume() betreten");
}

protected void onPause() {
    super.onPause();
    Log.v(OUTER_TAG, "4. Stufe: onPause() betreten");
}

protected void onStop() {
    super.onStop();
    Log.v(OUTER_TAG, "5. Stufe: onStop() betreten");
}

protected void onRestart() {
    super.onRestart();
    Log.v(OUTER_TAG, "Wiederaufnahme: onRestart() betreten [nach Stufe 5, vor Stufe 2]");
}

protected void onDestroy() {
    super.onDestroy();
    Log.v(OUTER_TAG, "6. Stufe: onDestroy() betreten");
}

...

Jede der sieben Callback-Methode soll durch Ausgabe einer kurzen Log-Meldung darüber informieren, dass sie vom Android System aufgerufen wurde. Den Verlauf der Log-Meldungen können wir dann im Logcat Tool Window von Android Studio analysieren und auf diese Weise die internen Vorgänge unserer App kenntlich machen.

Hinweis: In jeder dieser Callback-Methoden wird als Erstes die Implementierung der Basisklasse von uns aufgerufen, bevor der eigene Code beginnt. Dadurch wird sichergestellt, dass die Default-Implementierung des jeweiligen Lifecycle Callbacks seine Aufgaben ausgeführt hat, bevor unser eigener Quellcode ausgeführt wird.

Wie an den Log-Meldungen zu erkennen ist, haben wir jeder Haupt-Callback Methode eine Stufe zugewiesen. So kann schnell in der Konsole erkannt werden, in welcher Stufe sich die Activity gerade befindet und welche Stufen vorher durchlaufen wurden, um zu der aktuellen Stufe zu gelangen.

Nur der onRestart() Methode wurde keine Stufe zugewiesen, da sie als Wiederaufnahme-Callback Methode angesehen werden kann, die aufgerufen wird, um die Ausführung der Activity wieder aufzunehmen. Sie führt die Activity mit Hilfe der Methoden onStart() und onResume() vom Stopped State (Stufe 5) in den Resumed State (Stufe 3).

2.1 Einfügen der Callback-Methoden in die MainActivity-Klasse

Um die oben aufgeführten Callback-Methoden in die MainActivity-Klasse einzufügen und die Logging-Konstante der äußeren Klasse umzubenennen, öffnen wir die Klassendatei MainActivity.java im Editor von Android Studio mit einem Doppelklick auf ihren Dateinamen im Project Tool Window. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.zitate unseres Projekts.

In dem unten aufgeführten Quellcode der MainActivity.java Datei wurden die Änderungen bereits durchgeführt und die eingefügten bzw. überarbeiteten Codezeilen markiert:

An dieser Stelle endet der freie Inhalt dieser Lektion. Wir hoffen, sie hat dir bis hierher gefallen! Du kannst sie im geschützten Bereich von ProgrammierenLernenHQ fortsetzen, in welchem sich alle Lektionen unserer Android Online-Kurse befinden.

Unsere Android Kurse bestehen aus insgesamt 43 großen Lektionen und sind unterteilt in 13 frei zugängliche und 30 Premium-Lektionen. Die Premium-Lektionen befinden sich in dem geschützten Bereich und sind nur für Käufer unseres Android Online-Kurs Gesamtpaket zugänglich.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813 An dieser Stelle endet der freie Inhalt dieser Lektion. Wir hoffen, sie hat dir bis hierher gefallen! Du kannst sie durch Kauf unseres Android Online-Kurs Gesamtpakets freischalten.

In unserem Android Online-Kurs Gesamtpaket befinden sich 43 große Lektionen, in denen wir dir schrittweise zeigen, wie voll funktionstüchtige Android Apps programmiert werden.

Diese Lektion ist Teil unseres Android Gesamtpakets. Insgesamt sind unsere Online-Kurse unterteilt in 13 frei zugängliche und 30 Premium-Lektionen.

Die Premium-Lektionen befinden sich in dem geschützten Bereich und sind nur für Käufer des Android Online-Kurs Gesamtpakets zugänglich.



Welche Inhalte befinden sich im Android Online-Kurs Gesamtpaket?

  • Das Gesamtpaket enthält alle Android Online-Kurse von ProgrammierenLernenHQ.
  • Im Paket enthalten ist unser großer Android Apps Programmieren Online-Kurs. Er ist unser Hauptkurs und besteht aus 35 großen Lektionen. Die Grundlagen der Android App Entwicklung praxisnah und verständlich zu lehren, ist das Hauptziel des Android Apps Programmieren Kurses.
  • Im Paket enthalten ist auch unser SQLite Datenbank App Programmieren Online-Kurs. Dieser Spezialkurs besteht aus 8 großen Lektionen und ist als weiterführender Kurs konzipiert worden. Der Kurs schließt an unseren Android Apps Programmieren Hauptkurs an und widmet sich dem speziellen Thema der SQLite Datenbanken.
  • Durch den Kauf erhältst du unbegrenzten Zugang zu allen Inhalten unseres Android Online-Kurs Gesamtpakets. Wir werden in Zukunft weitere Lektionen hinzufügen. Auch auf alle zukünftigen Lektionen erhältst du vollen Zugriff.

Wir hoffen, Dich bald als neuen Kursteilnehmer unserer Android Online-Kurse begrüßen zu dürfen!

Einmal kaufen und dadurch zeitlich unbegrenzten Zugriff auf alle Inhalte unseres Android Online-Kurs Gesamtpakets erhalten.



Hinweis: Der untere Quellcode ist Teil des geschützten Bereichs von ProgrammierenLernenHQ. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte.
Erfahre mehr über unsere Android Online-Kurse.

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

In den oben aufgeführten Quellcode der MainActivity-Klasse wurden mehrere Callback-Methoden eingefügt und eine Änderung an der bereits vorhandenen onCreate() Callback-Methode vorgenommen. Zudem wurde die Logging-Konstante umbenannt.

In Zeile 27 wurde die Logging-Konstante von LOG in OUTER_TAG umbenannt. Dadurch können wir besser zwischen den Logging-Tags der äußeren und inneren Klasse unterscheiden.

In Zeile 37 wurde ein Methodenaufruf eingefügt, durch den die Activity eine kurze Meldung an die Konsole ausgibt, sobald die onCreate() Methode betreten wird. Als Log-Text wird „1. Stufe: onCreate() betreten“ ausgegeben. So kann später direkt im Logcat Tool Window von Android Studio erkannt werden, wann die erste Lifecycle Callback Methode betreten wurde.

In den Zeile 51 bis 85 wurden sechs weitere Callback-Methoden eingefügt. Diese sind die Methoden onStart(), onResume(), onPause() , onStop(), onRestart() und onDestroy(). Jede dieser eingefügten Callback-Methoden gibt eine kurze Log-Meldung aus, über die sie mitteilt, dass sie gerade betreten wurde, also kurz vorher vom Android System aufgerufen worden ist.

In Android Studio sollte die MainActivity.java Klassendatei nun wie folgt aussehen:

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

In der oberen Abbildung ist die überarbeitete MainActivity.java Klassendatei dargestellt. Es sind nur diejenigen Methoden aufgeklappt, an denen auch Änderungen vorgenommen wurden. Am Quellcode wurden zwei Erweiterungen und eine Umbenennung durchgeführt. Welche Bedeutung der jeweilige Code-Block besitzt, ist in der unteren Liste angegeben:

  1. A – Die Logging-Konstante der äußeren Klasse wurde von LOG in OUTER_TAG umbenannt.
  2. B – In der bereits vorhandenen onCreate() Callback-Methode wird nun eine Log-Meldung ausgegeben.
  3. C – Sechs weitere Callback-Methoden wurden der MainActivity-Klasse hinzugefügt. Jede gibt eine Log-Meldung aus.

Wir haben nun die Android Activity Lifecycle Methoden unserer MainActivity-Klasse hinzugefügt. Unsere Android App wird dadurch mehrere kurze Log-Meldungen ausgeben und uns über ihre inneren Zustände informieren. Die ausgegebenen Log-Meldungen werden wir im nächsten Abschnitt analysieren, wenn wir unsere App auf einem Android Gerät ausführen lassen.

3. Ausführen und Testen unserer Android App

Wir werden nun unserer Android App auf einem Android Virtual Device im Emulator ausführen lassen. Dabei möchten wir die Log-Meldungen unserer Anwendung in Echtzeit verfolgen und analysieren, wann sie sich in welchem Zustand befindet und wie die Zustandsübergänge stattfinden.

Unsere App starten wir dazu wie gewohnt über den Run > Run 'app' Menüeintrag, den wir über die obere Menüleiste erreichen.

Sobald unsere Android App auf dem AVD gestartet wurde, werden von den hinzugefügten Android Activity Lifecycle Methoden mehrere Log-Meldungen an die Konsole ausgegeben. Die ausgegebenen Meldungen können wir im Logcat Tool Window von Android Studio folgendermaßen betrachten:

  1. Wir öffnen das Logcat Tool Window mit einem Klick auf den Logcat-Tab am unteren Bildschirmrand.
  2. In der Drop-Down Liste stellen wir die Prioritätsstufe auf Verbose ein.
  3. In das anschließende Suchfeld geben wir MainActivity als Suchbegriff ein.
  4. Für die hintere Drop-Down Liste stellen wir sicher, dass der Eintrag Show only selected application ausgewählt ist.
android lifecycle log

Unsere App wurde gerade gestartet, ist im Bildschirmvordergrund und besitzt den Benutzer-Fokus. Sie befindet sich nun im Resumed State.

In der oberen Abbildung ist die Logcat-Ausgabe unserer Android App zu sehen. Unsere Anwendung wurde gerade gestartet, ist im Bildschirmvordergrund und besitzt den Benutzer-Fokus. Sie befindet sich momentan im Resumed State, welchen sie über die Callback-Methoden onCreate(), onStart() und onResume() erreicht hat.

Als Nächstes lassen wir unsere App und dadurch auch die MainActivity in den Bildschirmhintergrund rücken. Dazu navigieren wir durch Drücken des Home-Buttons zu dem Home Screen des Android Geräts.

Als Ergebnis erhalten wir folgende Log-Meldungen in Android Studio angezeigt:

lifecycle_log

Unsere Activity ist in den Hintergrund gerückt und wird nun vollständig überdeckt. Sie befindet sich nun im Stopped State.

Das Android System hat die MainActivity in den Hintergrund rücken lassen, dazu hat es die onPause() und onStop() Methoden aufgerufen. Unsere App mit ihrer Activity wird nun vollständig überdeckt und besitzt keinen Benutzer-Fokus mehr. Sie ist aber nicht zerstört worden, sondern noch vollständig intakt.

Wir öffnen nun erneut unsere Anwendung. Dazu navigieren wir in das Alle Apps-Menü und klicken auf das Symbol der Zitate-App. Daraufhin wird unsere App wieder fortgesetzt und rückt in den Bildschirmvordergrund.

Als Ergebnis erhalten wir folgende Log-Meldungen in Android Studio angezeigt:

lifecycle_log_activity

Unsere App wurde erneut geöffnet. Dadurch wurde die Activity wieder fortgesetzt und vom Stopped State in den Resumed State übergegangen.

Unsere App wurde nun wieder fortgesetzt. Das Android System hat dazu die Wiederaufnahme-Methode onRestart() aufgerufen, wodurch die Activity von Stufe 5 in Stufe 2 übergeht und der Restart-Pfad durchlaufen wird. Nachdem die onRestart() Methode ausgeführt wurde, wird sofort die onStart() Methode und danach die onResume() Methode gestartet.

Unsere Activity hat nun wieder den Resumed State betreten, besitzt den Benutzer-Fokus und befindet sich vollständig im Bildschirmvordergrund. Alle ihre Eigenschaften konnten vom Android System wiederhergestellt werden, da eine Instanz der Activity im Speicher gehalten wurde, während sie sich im Stopped State befand.

Als letzten Schritt möchten wir unsere Android App beenden. Mit einem Klick auf den Back-Button verlassen wir unsere App, worauf sich folgende Log-Meldung ergibt:

lifecycle_log_android_activity

Unsere App wurde mit dem Back-Button geschlossen. Das Android System hat daraufhin die Activity endgültig beendet und dabei zerstört.

Die Activity wird, durch das Verlassen der App mittels Back-Button, nun vom Android System vollständig und endgültig zerstört. Dabei wird zuerst die onPause() Methode aufgerufen, danach die onStop() Methode und schließlich die onDestroy() Methode, in welcher die Activity vollständig zerstört wird.

Die MainActivity ist jetzt endgültig zerstört worden. Es wurde vom Android System nicht versucht den Zustand der Activity zu speichern, da Android davon ausgeht, dass der Benutzer mit der Activity fertig ist und daher nicht erwartet, dass der Activity-Zustand gespeichert wird. Dies ist so in dem Android System konzipiert und sollte von Android-Entwicklern gut verstanden werden.

Zusammenfassung

In dieser Lektion haben wir den Lebenszyklus von Android Anwendungen, den Android Activity Lifecycle, kennengelernt. Wir haben erfahren, welche Zustände eine Activity in Android im Laufe ihres Lebens durchläuft und auf welche Weise sie zwischen den Zuständen wechselt.

Da der Android Activity Lifecycle für die Entwicklung komplexer Android Apps von zentraler Bedeutung ist, haben wir ihn im theoretischen Teil dieser Lektion besonders ausführlich behandelt. Dabei haben wir erfahren, wie das Android System den Zustand einer Activity mit Hilfe von Lifecycle Callback Methoden ändert.

Die verschieden Lifecycle-Methode haben wir anschließend in der MainActivity-Klasse unserer Android App so implementiert, dass von ihnen kurze Log-Meldungen ausgeben werden, die über die internen Abläufe der Activity informieren. Auf diese Weise konnten wir uns die einzelnen Lebensphasen unserer MainActivity direkt im Logcat Tool Window anzeigen lassen und somit die internen Vorgänge besser nachvollziehen.

Abschließend haben wir unsere Android App im Emulator auf einem Android Virtual Device ausgeführt und anhand der Log-Meldungen überprüft, welche Zustände von unserer Activity durchlaufen und wann welche Lifecycle-Methoden zur Zustandsänderung vom Android System aufgerufen werden.

In der nächsten Lektion werden wir uns weiter mit dem Android Activity Lifecycle beschäftigen. Wir werden lernen wie man den Zustand der MainActivity speichern und wieder laden kann, falls die Activity aufgrund von Systembeschränkungen vom Android System zerstört werden musste. Dies werden wir mit Hilfe der Callback-Methoden onSaveInstanceState() und onRestoreInstanceState() realisieren.

Weiterführende Literatur




Comments 38

  1. Hallo Chris,
    eine gelungenes Lernprogramm!
    Für mich als Einsteiger ist es wichtig Zusammenhängen zu erkennen.
    Was in Büchern auf 100 Seiten dargelegt ist schaffst Du auf einer Seite.
    Super!

    1. Post
      Author

      Hallo Kurt,

      vielen Dank für dein Lob! Schön, wenn die Zusammenhänge trotz Komplexität des Themas noch erkannbar bleiben.

      Viele Grüße, Chris

  2. Hallo,
    zuerst einmal wollte ich sagen das ich das Tutorial als sehr gut gemacht empfinde.

    Und nun zu meiner Frage:
    Da ich jetzt etwas Blut geleckt habe wollte ich fragen wie es ist wenn ich den hier gezeigten Code weiterentwickeln möchte und diese Weiterentwicklung dann veröffentlichen möchte? Gibt es da eine Lizenz die das regelt? Oder ist das nicht möglich?

    1. Post
      Author

      Hallo Julian,

      den Code aus meinen Tutorials kannst du gerne für deine eigenen Apps verwenden.

      Viele Grüße, Chris

  3. Hallo Chris,
    auch ich möchte mich für dieses sehr ausführliche Tutorial bedanken. Es muss sehr aufwändig gewesen sein, dies zu schreiben. Dafür zolle ich dir Respekt! Und durch dieses Tutorial bin ich ermutigt, weiter zu machen.
    Viele Grüßé, Martin

    1. Post
      Author

      Hallo Martin,

      danke für dein Lob! Ja es ist sehr zeitaufwendig diese Art von Tutorials zu erstellen. Die positiven Rückmeldungen der Leser sind da natürlich eine große Freude. Da weiß man, dass sich der ganze Aufwand gelohnt hat.

      Viele Grüße, Chris

  4. Ein Wort: DANKE!

    In den letzten beiden Wochen habe ich mich durch das Tutorial gearbeitet und ein gutes Verständnis dafür bekommen, wie die Entwicklung von Android Apps funktioniert.

    Auch wenn noch vieles zu erkunden sein wird, fühle ich mich jetzt für mein nächstes Vorhaben gut gerüstet und werde sicherlich noch oft hier nachschlagen!

    Liebe Grüße,
    Gert

    1. Post
      Author

      Hallo Gert,

      danke für dein Lob und gutes Gelingen beim Entwickeln eigener Apps!

      Viele Grüße, Chris

  5. Hi Chris,

    danke für dieses Tutorial. Ich habe selbst schon Tutorials verfasst und weiß, dass es mitunter schwer ist die richtige Balance aus Theorie und Praxis zu finden. Oft geht die Kurweiligkeit und der rote Faden verloren. Daher bin ich begeistert, wie Sie dieses Tutorial strukturiert haben. Ich hatte keine Ahnung von der Materie und fand mich doch nie verloren. Hab ich mal ein vorher erwähntes Detail zur Umsetzung vergessen, wurde es garantiert wiederholt. Und so hat ihr Tutorial mir nicht nur Wissen vermittelt, sondern dieses auch verfestigt.

    Tausend Dank! Nun fühle ich mich sicher genug mein eigenes erstes Projekt zu starten und komme bestimmt zurück um die weiterführenden Links zu nutzen 🙂

    Liebe Grüße, Jonathan

    1. Post
      Author

      Hallo Jonathan,

      vielen Dank für Deine lobenden Worte. Hat mich sehr gefreut 🙂

      Viele Grüße und viel Erfolg + Spaß am eigenen Projekt,
      Chris

  6. Hey Chris,

    ich danke Dir und der Webseite „https://www.programmierenlernenhq.de/“ für dieses tolle Tutorial mit den interessanten 15 Lektionen. Der ganze Stoff wird verständlich erklärt und das Wichtigste wird auf den Punkt gebracht.
    Ich hatte sehr viel Spaß beim Durcharbeiten des Tutorials und habe einiges an Wissen angeeignet, was ich sonst aufwendig zusammenkratzen müsste.

    1. Post
      Author

      Hallo M Ali Ö,

      danke für Dein Lob! Es freut mich immer sehr, wenn ich am Ende der 15 Lektionen Feedback erhalte.

      Viele Grüße, Chris

  7. Hallo Chris,
    vielen Dank für dieses wirklich tolle Tutorial!!!
    Ich wollte nur mal in die ANDROID Programmierung reinschnuppern, war aber dann aber bis zum Schluss mit großem Interesse dabei.
    Super gemacht!!!

    1. Post
      Author

      Hallo Oliver,

      danke für die lobenden Worte und super, dass du bis zum Schluss durchgehalten hast.

      Viele Grüße, Chris

  8. Hallo Chris,
    großes Lob und vielen Dank für dieses tolle Tutorial! Ich bin total begeistert vom übersichtlichen Aufbau und der Step-by-Step-Heranführung an das Thema. Selbst komplexe Dinge sind sehr gut verständlich und auch für Anfänger nachvollziehbar erklärt: Respekt!
    Viele Grüße von
    Gerry

    1. Post
      Author
  9. Hi Chris,

    mittlerweile bin ich wieder ein Stückchen weiter gekommen. Wenn ich jeweils den Quellcode so nutze wie du ihn vorgibst krieg ich zu Punkt 7.2 nicht das richtige log-Protokoll.

    Klar ist ich wähle mir im Suchfenster des Android Monitors „MainActivity“ aus. Starte ich die App, folgt bei mir gemäß deiner ersten Abbildung in 7.2 korrekt die Folge von
    onCreate -> onStart -> onResume

    Wenn ich nun auf ein Listenelement klicke um die Details zu sehen kommt:
    onPause -> onStop -> onDestroy
    anstelle nach onStop aufzuhören.
    Logischerweise schreibt mir das log-Protokoll, wenn ich in der App auf den „up“ Button drücke um zur App zu gelangen, anstelle von
    onRestart -> onStart -> onResume lediglich wieder
    onCreate -> onStart -> onResume da ja die Daten zerstört und damit nicht wiederhergestellt werden können.

    Aus deiner Erklärung nach Fließdiagramm unter 1.2 gibt es von „onStop“ drei Wege um insgesamt wieder zu „onResume“ zu kommen.
    1) „User navigiert zu der Activity“, was offenbar nicht funktioniert, da die Activity bei mir gleich zerstört wird.
    2) „Apps mit höherer Priorität benötigen Speicherplatz“, da bei mir jedoch „onDestroy“ steht glaube ich nicht dass es ein Prioritätsproblem ist. An zu wenig Cache-Speicher kann es nicht liegen. Hab ihn grad bereinigt und den Vorgang wiederholt. Mit gleichem Ergebnis
    3) „Activity wird beendet oder vom System zerstört“ heißt bei mir wird die eine Activity komplett zerstört und die nächste kreiert… warum verstehe ich aber nicht.

    Ich hoffe du kannst mir helfen.

    Lieben Gruß
    Sebastian

    1. Post
      Author

      Hallo Sepp,

      hört sich ja spannend an. Ich würde gerne mal deinen Quellcode bei mir ausprobieren, um zu sehen, ob bei mir das gleiche App-Verhalten auftritt. Wenn du möchtest, kannst Du mir deine Projektdateien (den ganzen Android Studio Projektordner, aber OHNE die build-Unterordner) als ZIP per E-Mail zusenden. Die E-Mail Adresse kannst Du im Impressum finden. Ich schaue dann mal was passiert.

      Viele Grüße, Chris

  10. Hallo,

    habe große Android Tutorial durchgearbeitet und bin von diesem total begeistert. Dies ist durch seine prägnante und ausführliche Beschreibung mit Abstand das beste Onlinetutorial, was ich je genutzt hab.

    An dieser Stelle ein großes Lob und Danke an Chris.

    Gruß Daniel

    1. Post
      Author
  11. Hallo Chris!

    Wollte mich den Vorrednern anschließen und mich auch für das wirklich gut gemachte Tutorial bedanken! Herzlichen Dank!

    Beste Grüße,
    Valjean

    1. Post
      Author

      Hallo Valjean,

      vielen Dank für dein Lob! Es freut mich, wenn das Tutorial bis Teil 15 durchgezogen wird.

      Viele Grüße, Chris

    1. Post
      Author
  12. Ah, hab’s grad gefunden. Im File AktiendetailActivity.java hatte ich in „onOptionsItemSelected“ ein „return true“ statt „return super.onOptionsItemSelected(item)“. Das kommt davon, wenn man selber am Code rumschraubt 😉

    Gruss,

    André

    1. Post
      Author

      Hallo André,

      ohh, das war ein gut versteckter Fehler. Gut wenn die App jetzt wie erwartet läuft.

      Viele Grüße, Chris

  13. Hallo Chris!

    Erst mal vielen Dank für das tolle Tutorial! Ich hab‘ das Problem, dass mein Up-Button nicht funktioniert. Könntest du bitte den gesamten Sourcecode irgendwo hinlegen, damit ich den Fehler eruieren kann?

    Gruss,

    André

    PS: Am Manifest liegt’s schon mal nicht 😉

  14. Hi Chris,

    vielen Dank für das super Tutorial!!!!
    Es ist echt klasse!!!!
    Weiter so………

  15. Hallo Chris,

    Ich wollte mich am Ende für dieses Tutorial bedanken!
    Es hat mir sehr geholfen und mich sehr viel mehr verstehen lassen!

    Viele Grüße,

    Daniel 🙂

    1. Post
      Author

      Hallo Daniel,

      danke für Deine lobenden Worte!

      Wir freuen uns am meisten, wenn die Tutorial Beiträge unseren Lesern weiterhelfen.

      Viele Grüße, Chris

    1. Hallo, Chris,
      nach einigem Herumprobieren habe ich jetzt eine funktionierende Lösung. Ich vermute, mein Problem entsteht durch das Zusammenspiel zwischen dem NavigationDrawerFragment, der MainActivity und dem SlapDataFragment, denn die Activity kontrolliert beides:

      public class MainActivity extends Activity
              implements NavigationDrawerFragment.NavigationDrawerCallbacks,
              SlapDataFragment.OnFragmentInteractionListener
      

      Der Test des Rückspeicherns des EditText-Feldes in der onCreateView-Methode zeigte, dass diese Methode 2-mal aufgerufen wird. Das brachte mich auf die Idee, den Wert zwischenzuspeichern und erst bei onActivityCreated dem EditText-Feld zu übergeben.
      Das Speichern habe ich gleich bei onCreate gemacht und sichergestellt, das der Wert nur in die Variable kommt, wenn savedInstanceState != null ist.
      Außerdem musste ich die Variable static definieren:

      SlapDataFragment

      1. Variablen vereinbaren
          // Schlüssel für die Übergabe des Inhaltes von editTextNewSlapData
          private static final String STATE_EDITTEXT_NEWSLAPDATA = "state_edit_text_new_slap_data";
          private static CharSequence mNewTitleRestore;               // Inhalt editTextNewSlapData
      2. Inhalt EditText-Feld sichern 
          @Override
          public void onSaveInstanceState(Bundle outState) {
              super.onSaveInstanceState(outState);
              // Inhalt editTextNewSlapData merken
              final EditText editTextNewTitel = (EditText) getActivity().findViewById(R.id.editTextNewSlapData);
              CharSequence newTitle = editTextNewTitel.getText();
              outState.putCharSequence(STATE_EDITTEXT_NEWSLAPDATA, newTitle);
          }
      3. Wert in Variable speichern
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
      
              if (getArguments() != null) {
                  // Inhalt EditText-Feld in Variable zurückzuschreiben
                  if (savedInstanceState != null) {
                      CharSequence newTitleRestore = savedInstanceState.getCharSequence(STATE_EDITTEXT_NEWSLAPDATA);
                      mNewTitleRestore = newTitleRestore;
                  }
                  // Parameter in Variable speichern
                  mItemNumber = getArguments().getInt(ARG_ITEM_NUMBER);
              }
          }
      4. Rückschreiben in editTextNewTitel 
          public void onActivityCreated(Bundle savedInstanceState) {
              super.onActivityCreated(savedInstanceState);
              // Inhalt editTextNewTitel wiederherstellen
              final EditText editTextNewTitel = (EditText) getActivity().findViewById(R.id.editTextNewSlapData);
              editTextNewTitel.setText(mNewTitleRestore);
      

      Viele Grüße und noch einmal vielen Dank für Deine Mühe!

      Bärbel

    2. Post
      Author

      Hallo Bärbel,

      schön wenn es nun funktioniert. Die Lösung ist ja doch schon etwas komplexer. Wahrscheinlich wird jedes Mal eine komplett neue EditText-Instanz erzeugt und damit geht der eingegebene Text verloren. Daher muss deine Speicher-Variable wohl static sein und wird über alle Instanzen geteilt.

      Viele Grüße, Chris

  16. Hallo Chris,

    vielen Dank für die schnelle Antwort!

    Den Textfeld-Wert, der in der Methode onSaveInstanceState() ausgelesen und abgespeichert wird hatte ich bei meiner Fehlersuche als 1. überprüft. Er war richtig und wurde im Bundle gespeichert.

    Ebenso hatte ich die ID des EditText-Feldes, die es meiner Meinung nach besitzt, kontrolliert:

    Heute habe ich, leider erfolglos, noch folgendes getestet:

    1. IDs vergeben, für die horizontalen LinearLayouts, die das EditText-Feld beinhalten.
    2. Die Anleitung von bei techotopia.com nutzt CharSequence  statt String. Die EditText-Felder wurden final gesetzt. Ich habe das eingearbeitet und getestet.
          @Override
         public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            // Inhalt editTextNewTitel merken
            final EditText editTextNewTitel = (EditText) getActivity().findViewById(R.id.editTextNewSlapData);
            CharSequence newTitle = editTextNewTitel.getText();
            outState.putCharSequence(STATE_EDITTEXT_NEWSLAPDATA, newTitle);
        }
    
       @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            if (savedInstanceState != null) {
                CharSequence newTitleRestore =  savedInstanceState.getCharSequence(STATE_EDITTEXT_NEWSLAPDATA);
                final EditText editTextTitel = (EditText) getView().findViewById(R.id.editTextNewSlapData);
                // Inhalt editTextNewTitel wiederherstellen
                editTextTitel.setText(newTitleRestore);
       }
    	…
    a) Ausgabe nach outState.putCharSequence(STATE_EDITTEXT_NEWSLAPDATA, newTitle); zeigte, das  der Wert im Bundle gespeichert ist.
    b) Ausgabe auf editTextTitel.setText(newTitleRestore); zeigte, das  der Wert in das EditText-Feld zurückgeschrieben wurde.
    Analoge Ergebnisse hatte ich zuvor. Danach müsste eigentlich das EditText-Feld einen Inhalt haben. 
    3. Ich habe die Anweisungen zum Wiederherstellen des Wertes des EditText-Feldes in die Methode onCreateView() verschoben:
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // für SmartPhones und Tablets das jeweils richtige Layout erzeugen und zurückgeben
    View slapDataView = inflater.inflate(R.layout.fragment_slap_data, container, false);
    if (savedInstanceState != null) {
    	  CharSequence newTitleRestore = savedInstanceState.getCharSequence (STATE_EDITTEXT_NEWSLAPDATA);
    	  final EditText editTextTitel = (EditText) slapDataView.findViewById(R.id.editTextNewSlapData);
    	 // Inhalt editTextNewTitel wiederherstellen
    	editTextTitel.setText(newTitleRestore);
    }
    return slapDataView;
    }
    

    Hierbei habe ich getView() durch die bereits definierte slapDataView ersetzt, da ansonsten das System abstürzte: Siehe logcart-Ausgabe unten als Anhang. Dabei ist Zeile 121 die mit getView().
    Der Test brachte ähnliche Ergebnisse. Setze ich die App allerdings fort, so kommt das System ein 2. mal zu einem Breakpoint auf if (savedInstanceState != null) { , wobei savedInstanceState = null ist.

    Leider weis ich nicht mehr weiter.

    Viele Grüße

    Bärbel

    (Anhang logcat-Ausgabe) *habe ich zur besseren Übersicht entfernt [Chris]

    1. Post
      Author

      Hallo Bärbel,

      hmm, da kann ich auf die Entfernung leider auch nicht weiterhelfen. Sorry. Ich werde mal in Zukunft etwas mit EditText-Feldern experimentieren und vielleicht kann ich dabei etwas Nützliches herausfinden, was dir helfen könnte. Aber im Moment weiß ich auch keinen Ratschlag mehr dazu.

      Viele Grüße, Chris

  17. Hallo Chris,

    lang habe ich, die noch eine Anfängerin auf dem Gebiet de Android-Programmierung ist, vergeblich nach einem guten Tutorial gesucht. Deine Reihe „Apps für Android entwickeln“ hat mir durch die sehr klare, detaillierte und verständliche Art der Darstellung vieles verständlich gemacht und sehr geholfen. Vielen Dank dafür!

    Zur Zeit habe ich an Hand des Teils 15 versucht, ein Problem in meiner Programmierung zu lösen. Leider ist mir das nicht gelungen:

    Ich erstelle ein Projekt mit minSdkVersion 16 und targetSdkVersion 22 und habe eine NavigationDrawer-Activity. Deren erster Eintrag erzeugt ein Fragment mit einer ListView aus einer SQLite-DB, über der sich ein Eingabefeld für neue Titel und ein Add-Button befinden. Ein Listenklick ruft entweder eine Activity mit einem Details-Fragment auf oder ersetzt das Details-Fragment im Container neben der ListView. Deshalb habe ich 2 Layouts (sw600dp) für das ListView-Fragment.
    Das klappt soweit alles, aber beim Drehen des Bildschirms wird, wenn bereits etwas im Eingabefeld für einen neuen Titel steht, dieser Inhalt gelöscht.

    Entsprechend dem Tutorial habe ich nun versucht, die Eingabe zu retten.

    1. Direkt zu Beginn der Klasse habe ich eine Konstante definiert:
        private static final String STATE_EDITTEXT_NEWSLAPDATA = "state_edit_text_new_slap_data";
    2. Den Text im Eingabefeld habe ich gespeichert bei:
        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            // Inhalt editTextNewTitel merken
            EditText editTextNewTitel = (EditText) getActivity().findViewById(R.id.editTextNewSlapData);
            String newTitle = editTextNewTitel.getText().toString();
            outState.putString(STATE_EDITTEXT_NEWSLAPDATA, newTitle);
        }
    3. Zuerst in der onCreateView-Methode, dann als das nichts brachte in onActivityCreated habe ich versucht, den Inhalt zurückzuschreiben:
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            if (savedInstanceState != null) {
                String newTitleRestore = savedInstanceState.getString(STATE_EDITTEXT_NEWSLAPDATA, "");
                EditText editTextTitel = (EditText) getView().findViewById(R.id.editTextNewSlapData);
                // Inhalt editTextNewTitel wiederherstellen
                editTextTitel.setText(newTitleRestore);
            }
    

    Hast Du eine Idee, worin der Fehler besteht? Ich bin Dir für jede Hilfe dankbar.

    Viele Grüße

    Bärbel

    1. Post
      Author

      Hallo Bärbel,

      vielen Dank für das Lob!

      Zu deiner Frage. Normalerweise sollte das EditText-Feld seinen Inhalt selbständig zwischenspeichern, sobald es eine eigene ID besitzt. Die scheint bei dir aber nicht der Fall zu sein.

      Hast du einmal beim Debuggen überprüft, welcher Textfeld-Wert in der Methode onSaveInstanceState() ausgelesen und abgespeichert wird.

      Auf die Schnelle habe ich bei techotopia.com eine hilfreiche Anleitung gefunden, die genau dein Problem behandelt:

      Saving and Restoring the User Interface State of an Android Activity

      Viele Grüße, Chris

  18. Pingback: Android Tutorial: Das SwipeRefreshLayout in Android

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.