Android_Tutorial_Lektion28_fotolia_RA_Studio_46292813

Programmier Tutorial: Apps für Android entwickeln – Teil 28: Den Zustand von Activities in Android speichern und laden

Nachdem wir in der vorherigen Lektion den Android Activity Lifecycle mit seinen zugehörigen Lifecycle Callbacks kennengelernt haben, werden wir uns in dieser Lektion mit zwei weiteren wichtigen Callback-Methoden, der onSaveInstanceState() und onRestoreInstanceState(), beschäftigen.

Wir werden die beiden Callback-Methoden für das Speichern und Wiederherstellen des Activity-Zustands verwenden. In der onSaveInstanceState() Methode werden wir den Inhalt des ListViews, also die Elemente seiner Datenquelle, auslesen und in einem Bundle-Objekt ablegen.


In der onRestoreInstanceState() Methode werden wir aus diesem Bundle-Objekt die gespeicherten Daten wieder auslesen und mit ihnen die Datenquelle unseres ListViews füllen. Auf diese Weise können wir die ListView-Einträge wiederherstellen, nachdem die Activity vom Android System aufgrund von Systembeschränkungen zerstört werden musste.

Wann dies der Fall ist, also in welchen Situationen das Android System die Activity zerstört, werden wir im theoretischen Teil dieser Lektion ausführlich behandeln. Dabei werden wir uns auch mit den Fragen beschäftigen, welche Zustandsinformationen der Activity das Android System automatisch speichert und welche von uns manuell gesichert werden müssen.

Im praktischen Teil dieser Lektion werden wir zunächst die Hilfsmethode createJSONStringFromQuoteList() in der Hilfsklasse Utility implementieren. Sie wird für das Umwandeln einer Quote-Liste in einen JSON-String verantwortlich sein. Wir werden sie für das Speichern des ListView-Inhalts in der onSaveInstanceState() benötigen, da nur bestimmte Datentypen in das Bundle-Objekt abgelegt werden können.

Anschließend werden wir die beiden Methoden onSaveInstanceState() und onRestoreInstanceState() in der MainActivity-Klasse implementieren. Von der onSaveInstanceState() Methode werden wir den Inhalt unseres ListViews auslesen und in Form eines JSON-Strings in einem Bundle-Objekt ablegen lassen, sobald die Activity in den Hintergrund rückt und droht vom Android System zerstört zu werden.

Mit der onRestoreInstanceState() Methode werden wir die gespeicherten Inhalte wieder aus dem Bundle-Objekt auslesen und der ListView-Datenquelle hinzufügen. Auf diese Weise können wir den Zustand der vom Android System zerstörten Activity wieder vollständig herstellen.

Abschließend werden wir unsere Android App im Emulator auf einem Android Virtual Device ausführen und prüfen, ob der Zustand der MainActivity korrekt gespeichert und wiederhergestellt wird, falls die Activity zerstört wurde.

1. Den Zustand von Activities speichern und wiederherstellen

In der vorherigen Lektion haben wir den Lebenszyklus von Activities in Android näher kennengelernt. Wir wissen nach welchem Schema Activities vom Android System erstellt und nach einer gewissen Zeit wieder zerstört werden.

In dieser Lektion werden wir uns der Frage zuwenden, wie der letzte Zustand einer Activity, also kurz bevor sie vom Android System zerstört wird, konserviert werden kann. Und zwar so, dass all ihre Eigenschaften beim erneuten Erzeugen der Activity wieder hergestellt werden können.

Wir werden nun zunächst den Ablauf beschreiben, nach dem in Android der Zustand einer Activity gespeichert und wiederhergestellt wird. Anschließend werden wir klären, welche Zustandsinformationen vom Android System automatisch konserviert und in welchen Situationen die Callback-Methoden für das Speichern und Laden des Activity-Zustands aufgerufen werden.

1.1 Wie der Activity-Zustand in Android gespeichert wird

Wenn eine Activity pausiert oder gestoppt wird, weil sie bspw. in den Bildschirmhintergrund rückt, bleibt ihr Zustand vollständig erhalten. Während sie sich im Paused oder Stopped State befindet, wird die Instanz der Activity im Speicher gehalten. Alle Informationen über ihre Member- und Zustandsvariablen bleiben dadurch erhalten.

Die Activity bleibt während dieser Zeit vollständig intakt, obwohl sie nicht sichtbar ist. Rückt sie wieder in den Bildschirmvordergrund, stellt das Android System ihren Zustand wieder vollständig her. Dies ist möglich, da die Instanz der Activity nie verloren gegangen ist.

Wenn eine Activity jedoch vom Android System aufgrund von Speichermangel oder einer Konfigurationsänderung (z.B. Bildschirmrotation) zerstört werden muss, kann ihr letzter Zustand nicht automatisch vom Android System wiederhergestellt werden, da beim Zerstören der Activity auch ihre Instanz verloren ging.

Die Activity muss dann wieder von Grund auf neu erstellt werden. Damit in einem solchen Fall die Informationen über die Member- und Zustandsvariablen der Activity erhalten bleiben, müssen sie vor dem Zerstören der Activity-Instanz mit Hilfe der Callback-Methode onSaveInstanceState() in einem Bundle-Objekt gespeichert werden.

In der unteren Abbildung ist zu erkennen, über welche Pfade der Activity-Zustand gespeichert und wiederhergestellt wird:

save_state_activity

Den Zustand einer Activity in Android speichern und wiederherstellen

Bevor eine Activity vom Android System zerstört werden kann, muss es die onSaveInstanceState() Methode aufrufen. So ist sichergestellt, dass der Zustand der Activity konserviert werden kann. Beim Aufruf wird der onSaveInstanceState() Methode ein Bundle-Objekt übergeben, in welches die Zustandsinformationen gespeichert werden können. Dies geschieht mit Hilfe von Schlüssel-Wert Paaren (key-value pairs).

Wird eine vorher zerstörte Activity wieder neu erstellt, übergibt das Android System dieses Bundle-Objekt an die Lifecycle Callback Methoden onCreate() und onRestoreInstanceState(). In beiden Methoden kann das Wiederherstellen des Activity-Zustands mit Hilfe des Bundle-Objekts vorgenommen werden.

Wurde der Zustand nicht gespeichert oder existierte bisher kein vorheriger Zustand, weil die Activity erstmalig erzeugt wurde, ist der Wert des übergebenen Bundle-Objekts null.

1.2 Welche Zustandsinformationen werden vom Android System gespeichert

Das Android System ist in der Lage einige der Activity Zustandsinformationen selbst zu speichern. Diese Aufgabe übernimmt die Default-Implementierung der onSaveInstanceState() Methode. Daher ist es auch wichtig die Superklassen Implementierung mit super.onSaveInstanceState(savedInstanceState); als Erstes im Methodenrumpf aufzurufen.

Die Default-Implementierung ruft jede onSaveInstanceState() Methode jedes View-Objekts im Layout auf. Dadurch kann jeder View den eigenen Zustand speichern. Nahezu jedes Widget im Android Framework implementiert die onSaveInstanceState() Methode entsprechend. Ein EditTextWidget speichert den eingegebenen Text und ein CheckBoxWidget speichert, ob sie aktiviert ist oder nicht.

Es können aber nur die Zustände von Widgets gespeichert werden, wenn diesen eine eigene ID zugewiesen wurde. Besitzt ein Widget keine ID, kann das Android System den Zustand des Widgets nicht konservieren.

Die Default-Implementierung von der onSaveInstanceState() Methode hilft zwar den Zustand der Benutzeroberfläche zu speichern, die Membervariablen der Activity gehen jedoch verloren. Daher ist es oft notwendig die onSaveInstanceState() Methode mit einer eigenen Implementierung zu überschreiben.

Dabei darf nicht vergessen werden die Superklassen Implementierung von onSaveInstanceState() zu Beginn aufzurufen. Dieser Fall gilt auch, wenn für das Laden des Zustands die onRestoreInstanceState() überschrieben wird. Auch dann muss die Superklassen Implementierung von onRestoreInstanceState() an erster Stelle des Methodenrumpfs aufgerufen werden.

1.3 Wann wird die onSaveInstanceState() Methode aufgerufen

Der Zeitpunkt an dem die onSaveInstanceState() Methode vom Android System aufgerufen wird, ist klar vorgegeben. Ab Android 9.0 erfolgt der Aufruf der onSaveInstanceState() Methode direkt nach der onStop() Methode. Für alle früheren Versionen, also bis Android 8.0, erfolgt der Aufruf unmittelbar vor der onStop() Methode.

Ob die onSaveInstanceState() Methode vom Android System aufgerufen wird, ist jedoch von dem Grund abhängig, aus dem die Activity zerstört werden soll bzw. in den Bildschirmhintergrund rückte.

Wenn bspw. der Benutzer die Anwendung mit dem Back-Button schließt, wird der Zustand nicht gesichert und somit die onSaveInstanceState() Methode nicht aufgerufen. Android nimmt in diesem Fall an, dass der Benutzer die App explizit beendet und beim nächsten Start der App eine frische Anwendung erwartet.

Rückt die Activity in den Bildschirmhintergrund, weil bspw. eine andere Activity den Benutzer-Fokus erhält, ruft das Android System die onSaveInstanceState() Methode auf. In einem solchen Fall nimmt Android an, das der Benutzer mit der Activity noch nicht fertig ist und konserviert daher ihren Zustand.

Da die onSaveInstanceState() Methode nicht in jedem Fall aufgerufen wird, sollte mit ihr nur der Zustand der Benutzeroberfläche und der dafür benötigten Membervariablen gespeichert werden. Zum Speichern von persistenten Daten sollte sie nicht verwendet werden. Solche Operationen, wie das Speichern von Daten in eine Datenbank, sollten vorgenommen werden, wenn die Activity sich im Vordergrund befindet und den Benutzer-Fokus besitzt.

1.3.1 Situationen in denen die Activity vom Android System zerstört wird

Es gibt einige Szenarien, in denen das Android System die Activity aufgrund von normalen Anwendungsverhalten zerstört, bspw. wenn der Benutzer die App mit dem Back-Button beendet. In solchen Situationen speichert das Android System den Zustand der Activity nicht, da es annimmt, dass sie nicht länger benötigt wird. Dann geht auch die Activity-Instanz verloren und kann nicht wieder hergestellt werden.

In der unteren Übersicht sind Situationen aufgeführt, in denen die Activity aufgrund von normalen Anwendungsverhalten vom Android Systemzerstört und daher die onSaveInstanceState() Methode nicht aufgerufen wird:

  • Verlassen der App mit dem Back-Button – Das Android System wertet diese Situation als endgültiges Verlassen der Anwendung. Daher wird die onSaveInstanceState() Methode nicht aufgerufen und somit der Activity-Zustand nicht gespeichert. Die Activity-Instanz geht dabei für immer verloren.

  • Mit dem Up-Button zurück navigieren – In der Standardeinstellung der Activity interpretiert das Android System die Situation so, als ob der Benutzer zum Hauptbildschirm der App möchte und nicht das Wiederherstellen des vorherigen Zustands erwartet. Daher wird die onSaveInstanceState() Methode nicht aufgerufen und somit der Activity-Zustand nicht gespeichert. Die Activity-Instanz geht dabei für immer verloren.

  • Die Activity wird mit finish() beendet – Die Activity wird manuell beendet. Das Android System versucht daher nicht den Zustand zu erhalten. Auch in diesem Fall wird die onSaveInstanceState() Methode nicht aufgerufen und somit der Activity-Zustand nicht gespeichert. Die Activity-Instanz geht dabei für immer verloren.

Es gibt aber auch Szenarien, in denen das Android System die Activity zwar zerstören muss, dabei aber den Zustand der Activity konserviert, bspw. wenn eine Activity sich im Stopped State befindet und für lange Zeit nicht mehr verwendet wurde. In solchen Situationen speichert das Android System den Zustand der Activity, da es annimmt, dass sie später noch einmal benötigt wird und dann wiederhergestellt werden soll.

In der unteren Übersicht sind Situationen aufgeführt, in denen das Android System die Activity zwar zerstört, jedoch kurz vorher die onSaveInstanceState() Methode zum Speichern der Activity-Zustands aufruft:

  • Der App-Prozess wird direkt beendet – Das Android System benötigt Speicherplatz und schließt daher gestoppte und auch pausierte Anwendungen, indem es den zugehörigen Prozess direkt beendet. Vorher wird die onSaveInstanceState() Methode aufgerufen und somit der Activity-Zustand gespeichert. Die Activity-Instanz kann beim erneuten Erzeugen der Activity wieder vollständig hergestellt werden.

  • Rotation des Bildschirms – Wird die Orientierung des Android Geräts von Landscape auf Portrait gewechselt, tritt ein Orientation Configuration Change ein. In einem solchen Fall wird die angezeigte Activity vom Android System zerstört und sofort wieder neu erstellt. Vorher wird die onSaveInstanceState() Methode aufgerufen und der Activity-Zustand gespeichert. Die Activity-Instanz kann beim erneuten Erzeugen der Activity wieder vollständig hergestellt werden. Diese Situation ist ideal, um die Implementierung der onSaveInstanceState() Methode zu testen.

  • Weitere Konfigurationsänderungen – Die häufigste Konfigurationsänderung haben wir gerade im vorherigen Punkt kennengelernt, den Orientation Configuration Change. In Android sind aber noch viele weitere solcher Ereignisse definiert, die einen Configuration Change auslösen und zum Zerstören und Neuerstellen der Activity führen.

    Normalerweise bleibt die Konfiguration des Android Geräts unverändert. In speziellen Situationen kann es aber zu Änderungen der Konfiguration zur Laufzeit der App und somit auch ihrer Activity kommen. Ereignisse die zum Zerstören der Activity führen sind bspw. eine Änderung der Bildschirmorientierung, Eingabegeräts, Schriftgröße, Sprache, Bildschirmgröße, -layout und -auflösung.

    Tritt ein Configuration Change ein, wird die Activity vom Android System zerstört und sofort wieder neu erzeugt. Dieses Verhalten ist so konzipiert, damit sich die Activity an die neue Konfiguration durch automatisches Laden alternativer Ressourcen, die extra für die neue Konfiguration vorgesehen sind, anpassen kann.

    Bevor die Activity aufgrund eines Configuration Changes zerstört wird, ruft das Android System die onSaveInstanceState() Methode auf und der Activity-Zustand kann vollständig gespeichert werden. Auf diese Weise kann die Activity-Instanz beim erneuten Erzeugen der Activity wieder vollständig hergestellt werden.

1.4 Wann wird die onRestoreInstanceState() Methode aufgerufen

Der Zeitpunkt an dem die onRestoreInstanceState() Methode vom Android System aufgerufen wird, ist klar vorgegeben. Für alle Android Versionen erfolgt der Aufruf der onRestoreInstanceState() Methode direkt nach der onStart() Methode, wenn die Activity von Grund auf neu erstellt wird.

Ob die onRestoreInstanceState() Methode vom Android System aufgerufen wird, ist jedoch von dem Bundle-Objekt abhängig, in welchem die Zustandsinformationen der zerstörten Activity abgelegt worden sind. Nur wenn das Bundle-Objekt existiert, wird die onRestoreInstanceState() Methode auch vom Android System aufgerufen.

Eine Activity kann somit nur dann wiederhergestellt werden, wenn beim vorherigen Zerstören ein Bundle-Objekt erzeugt werden konnte. Dies ist nur in solchen Situationen möglich, in denen das Android System die onSaveInstanceState() Methode vor dem Zerstören der Activity aufruft. In der onSaveInstanceState() Methode kann dann das Bundle-Objekt erzeugt und mit Zustandsdaten befüllt werden.

Das erzeugte Bundle-Objekt wird im Systemspeicher von Android gehalten, daher sollte nur eine geringe Datenmenge in diesem Objekt gespeichert werden. Zudem merkt sich das Android System, welche zerstörte Activity zu dem Bundle-Objekt ehemals gehörte.

Navigiert der Benutzer zu einem späteren Zeitpunkt zur zerstörten Activity zurück, kann sie mit Hilfe des Bundle-Objekts wieder vollständig hergestellt werden. Das Android System übergibt das Bundle-Objekt zu diesem Zweck den onCreate() und onRestoreInstanceState() Methoden, in denen das Wiederherstellen des Activity-Zustands erfolgen kann. Die gespeicherten Informationen im Bundle-Objekt nennt man daher auch den Instance State der Activity.

1.5 Wie kann das Speichern des Activity-Zustands getestet werden

Eine sehr einfache Möglichkeit zu überprüfen, ob die eigene App in der Lage ist den Zustand ihrer Activities wieder herzustellen, ist das Rotieren des Android Geräts. Durch den Wechsel der Bildschirmausrichtung (screen orientation), zerstört das Android System die sichtbare Activity und erzeugt sie anschließend von Neuem.

Auf diese Weise wird vom System sichergestellt, dass die zur Verfügung stehenden Bildschirmressourcen optimal genutzt werden können, bspw. durch Verwenden eines alternativen Layouts. Schon alleine aus diesem Grund ist es wichtig, dass die Activities ihre Benutzeroberfläche vollständig wiederherstellen können. Denn Benutzer von mobilen Geräten verändern regelmäßig die Bildschirmausrichtung während des Nutzens einer Anwendung.

Wir werden in den nächsten beiden Abschnitten das Speichern des Activity-Zustands implementieren. Anschließend werden wir unsere Implementierung testen, indem wir durch Rotation der Bildschirmorientierung das Android System veranlassen unserer MainActivity zu zerstören und sofort wieder neu zu erzeugen.

2. Implementieren der createJSONStringFromQuoteList() Methode in der Utility-Klasse

Wir kommen nun zum praktischen Teil dieser Lektion, dem Implementieren der Callback-Methoden onSaveInstanceState() und onRestoreInstanceState() mit deren Hilfe der Zustand unserer MainActivity gespeichert und wiederhergestellt wird. Doch bevor wir die beiden Callback-Methoden implementieren können, muss noch die Hilfsmethode createJSONStringFromQuoteList() in der Utility-Klasse definiert werden.

Die Hilfsmethode werden wir später in der onSaveInstanceState() Methode nutzen, wenn wir den Inhalt des ListViews unserer Android App in dem Bundle-Objekt speichern werden. Sie wird aus einer Liste mit Zitat-Objekten einen JSON-String erstellen. Die Zitat-Objekte müssen in eine Zeichenkette umgewandelt werden, da beim Speichern des Activity-Zustands nur einfache Datentypen, wie Integer oder String, in dem Bundle-Objekt abgelegt werden können und keine Objekte.

Wir werden nun die Methode createJSONStringFromQuoteList() in der Utility-Klasse implementieren. Dazu öffnen wir die Klassendatei Utility.java im Editor von Android Studio, indem wir doppelt auf ihren Dateinamen im Project Tool Window klicken. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.zitate unseres Projekts.

In dem unteren Quellcode der Utility.java Datei sind die erforderlichen Maßnahmen bereits durchgeführt und die eingefügten Codezeilen markiert worden:

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.

Im oberen Quellcode der Utility-Klasse ist die neue Methode bereits hinzugefügt worden. Die eingefügten Zeilen sind grau markiert.

In den Zeilen 166 bis 190 wird die neue Methode createJSONStringFromQuoteList() definiert. Sie besitzt einen Parameter vom Datentyp List<Quote>, über den ihr die Zitat-Liste übergeben wird, und liefert als Rückgabewert einen String, der den Inhalt der Zitat-Liste im JSON-Format enthält, zurück.

Die createJSONStringFromQuoteList() Methode

Wir werden nun die createJSONStringFromQuoteList() Methode genauer betrachten. Zur Übersichtlichkeit ist die Methode an dieser Stelle nochmals aufgeführt:

public static String createJSONStringFromQuoteList(List<Quote> quoteList) {

    JSONObject quotesData = new JSONObject();
    JSONArray quotesArray = new JSONArray();

    try {
        for (Quote quoteObject:quoteList) {
            JSONObject quote = new JSONObject();
            quote.put("id", quoteObject.getImageId());
            quote.put("author", quoteObject.getQuoteAuthor());
            quote.put("text", quoteObject.getQuoteText());

            quotesArray.put(quote);
        }
        quotesData.put("quotes", quotesArray);

    } catch (JSONException e) {
        Log.e(TAG, "JSONException: " + e.getMessage());
    }

    String jsonString = quotesData.toString();
    Log.i(TAG, "Aus QuoteList generierter JSON-String: " + jsonString);

    return jsonString;
}

Die createJSONStringFromQuoteList() Methode wandelt eine Liste von Quote-Objekten in eine Zeichenkette im JSON-Format um. Dazu werden die Zitatinformationen aus der übergebenen Quote-Liste ausgelesen und in einem JSON-Objekt gespeichert. Das JSON-Objekt wird schließlich in eine Zeichenkette umgewandelt, in der sämtliche ausgelesene Zitate im JSON-Format enthalten sind.

Das Auslesen der Quote-Liste findet im try-Block in den Zeile 6 bis 17 statt. Für jedes in der Liste enthaltenes Quote-Objekt wird ein JSONObject erzeugt, welches in sich die Zitat-ID, den Autorennamen und den Zitattext aufnimmt. Jedes so erstellte JSONObject wird anschließend in den JSONArray quotesArray abgelegt.

Der mit Zitaten gefüllte JSONArray quotesArray wird anschließend in Zeile 15 als einzige Eigenschaft in das JSONObject quotesData mit dem Schlüssel quotes abgelegt. In dem JSONObject quotesData sind nun alle ausgelesenen Zitate enthalten. Zudem besitzt er exakt die gleiche Datenstruktur, wie sie von unserem Webserver generiert wird.

In Zeile 21 lassen wir das JSONObject quotesData in eine Zeichenkette umwandeln. Dazu nutzen wir die toString() Methode der JSONObject-Klasse. Der so erzeugte String enthält nun sämtliche ausgelesene Zitate im JSON-Format.

Besonders wichtig hierbei ist, dass die Daten in dem JSON-String exakt die gleiche Datenstruktur besitzen, wie sie auch der Webserver verwendet. Auf diese Weise ist sichergestellt, dass wir den erzeugten JSON-String später sehr einfach mit Hilfe der createQuotesFromJSONString() Methode auslesen und ihn in eine Liste mit Quote-Objekten umwandeln lassen können.

In Zeile 22 lassen wir zur Kontrolle den erzeugten JSON-String auf der Konsole als Log-Meldung ausgeben. So können wir später zur Laufzeit prüfen, ob die Zitatinformationen korrekt ausgelesen werden, und sicherstellen, dass sie in der Datenstruktur des Webserver abgelegt worden sind.

Den erzeugten JSON-String geben wir schließlich in Zeile 24 an die aufrufende Methode zurück. Dort kann er dann in dem Bundle-Objekt abgelegt und dadurch der Inhalt des ListViews konserviert werden.

Mit diesen Quellcodezeilen haben wir die Hilfsmethode createJSONStringFromQuoteList() implementiert. Sie wird für uns den Inhalt des ListViews, also die hinterlegt Liste mit Quote-Objekten, in einen JSON-String umwandeln. Alles was wir ihr dazu übergeben müssen, sind die ListView-Einträge in Form einer Quote-List.

In Android Studio sollte der Inhalt der Utility.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 Utility.java Klassendatei dargestellt. Dem Quellcode wurde nur die createJSONStringFromQuoteList() Methode (Markierung A) hinzugefügt. Sie ist als einzige Methode aufgeklappt. Die vier anderen Methoden wurden nicht verändert und sind daher zugeklappt geblieben.

Da wir jetzt die createJSONStringFromQuoteList() Methode in der Hilfsklasse Utility erstellt haben, sind die Voraussetzungen für das Speichern des Activity-Zustands erfüllt.

Als Nächstes können wir daher die beiden Callback-Methoden onSaveInstanceState() und onRestoreInstanceState(), mit deren Hilfe der Zustand unserer MainActivity gespeichert und wiederhergestellt wird, implementieren. Die beiden Callback-Methoden sind Teil des Android Activity Lifecycles und müssen daher in der MainActivity-Klasse implementiert werden.

3. Implementieren der Callback-Methoden zum Speichern und Laden des Activity-Zustands in der MainActivity-Klasse

Durch das Implementieren der createJSONStringFromQuoteList() Methode in der Utility-Klasse, sind nun die Voraussetzungen für das Speichern des Activity-Zustands erfüllt. Wir können jetzt mit dem Implementieren der beiden Methode onSaveInstanceState() und onRestoreInstanceState() beginnen, über die der Zustand der MainActivity gespeichert bzw. anschließend wiederhergestellt werden kann.

Wir werden nun die beiden Callback-Methoden zum Speichern und Laden des Activity-Zustands in der MainActivity-Klasse implementieren. Dazu ö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 beiden Methoden onSaveInstanceState() und onRestoreInstanceState() bereits eingefügt. Zudem wurde eine weitere Konstante definiert, die als Schlüssel verwendet wird, unter dem der JSON-String in dem Bundle-Objekt abgelegt wird.

Alle in die MainActivity.java Datei neu hinzugefügten Codezeilen sind markiert worden:

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 wurde in Zeile 28 die Konstante LISTVIEW_DATA definiert. Sie enthält den Schlüssel, unter dem der JSON-String in dem Bundle-Objekt abgelegt wird.

In den Zeilen 53 bis 65 und den Zeilen 68 bis 85 werden die beiden Callback-Methode onSaveInstanceState() und onRestoreInstanceState() definiert. Mit ihrer Hilfe wird der Zustand der MainActivity gespeichert.

Die onSaveInstanceState() Methode

Wir werden nun die onSaveInstanceState() Methode genauer betrachten. Zur Übersichtlichkeit ist die Methode an dieser Stelle nochmals aufgeführt:

public void onSaveInstanceState(Bundle savedInstanceState) {
    // Die Superklasse muss immer als Erstes aufgerufen werden, so dass der Zustand
    // der View-Hierarchie vom Android System gespeichert werden kann
    super.onSaveInstanceState(savedInstanceState);
    Log.v(OUTER_TAG, "--> Zustand speichern: onSaveInstanceState() betreten");

    if (mQuoteList.size() > 0) {
        String jsonString = Utility.createJSONStringFromQuoteList(mQuoteList);
        savedInstanceState.putString(LISTVIEW_DATA, jsonString);
    } else {
        Log.v(OUTER_TAG, "--> Zitateliste ist leer. Zustand wurde nicht gespeichert.");
    }
}

Für das Speichern des Zustands der MainActivity müssen wir nur die Einträge des ListViews konservieren. Alle anderen Elemente der Benutzeroberfläche werden vom Android System automatisch gesichert. Damit es dies auch tatsächlich ausführen kann, muss unbedingt die Superklassen-Implementierung der onSaveInstanceState() Methode an erster Stelle aufgerufen werden. Dies geschieht in Zeile 4.

In Zeile 5 lassen wir eine Log-Meldung auf der Konsole ausgeben, die über das Betreten der onSaveInstanceState() informiert. Auf diese Weise können wir später im Logcat Tool Window von Android Studio analysieren, wann die Methode innerhalb des Android Activity Lifecycles vom Android System aufgerufen wird.

In Zeile 7 prüfen wir mit der if-Anweisung, ob die Datenquelle des ListViews mit Einträgen gefüllt ist. Nur wenn die Quote-Liste auch Einträge enthält, wird der if-Zweig betreten.

Ist dies der Fall, lassen wir in Zeile 8 die Datenquelle unseres ListViews mit Hilfe der createJSONStringFromQuoteList() Methode in einen JSON-String umwandeln. Die Datenquelle enthält alle Einträge des ListViews in Form einer Quote-Liste. Der JSON-String enthält somit alle Elemente der Quote-Liste, die in ihm in der vom Webserver verwendeten Datenstruktur im JSON-Format abgelegt sind.

Anschließend erfolgt in Zeile 9 das Speichern des erzeugten JSON-Strings. Dazu wird die putString() Methode auf dem Bundle-Objekt savedInstanceState aufgerufen. Ihr wird der Schlüssel LISTVIEW_DATA und der String-Wert jsonString übergeben.

Das Bundle-Objekt wird vom Android System zum Speichern und Wiederherstellen des vorherigen Activity-Zustands verwendet. Daher wird es auch als Instance State bezeichnet. Der Instance State ist somit eine Sammlung von Schlüssel-Wert Paaren (key-value pairs), die in einem Bundle-Objekt abgelegt werden.

In Zeile 8 werden also die ListView-Einträge in eine Form umgewandelt, in der sie in dem Bundle-Objekt unter einem einzigartigen Schlüssel abgelegt werden können. Anschließend werden die Einträge in ihrer neuen Form in Zeile 9 dem Bundle-Objekt hinzugefügt. Auf diese Weise wird der Zustand unseres ListViews konserviert und somit auch der Zustand unserer MainActivity.

Sollte die Datenquelle unseres ListViews leer sein, wird der else-Zweig betreten und in Zeile 11 eine Log-Meldung auf der Konsole ausgeben, welche über die leere Datenquelle und das Scheitern des Speichervorgangs informiert.

Die onRestoreInstanceState() Methode

Das Wiederherstellen des gespeicherten Zustand der MainActivity geschieht in der onRestoreInstanceState() Methode, die wir nun genauer betrachten wollen. Zur Übersichtlichkeit ist die Methode an dieser Stelle nochmals aufgeführt:

protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // Die Superklasse muss immer als Erstes aufgerufen werden, so dass der Zustand
    // der View-Hierarchie vom Android System wiederhergestellt werden kann
    super.onRestoreInstanceState(savedInstanceState);
    Log.v(OUTER_TAG, "<-- Zustand wiederherstellen: onRestoreInstanceState() betreten");

    String jsonString = savedInstanceState.getString(LISTVIEW_DATA);

    if (jsonString != null) {
        List<Quote> restoredQuoteList = Utility.createQuotesFromJSONString(jsonString);
        mQuoteList.clear();
        mQuoteList.addAll(restoredQuoteList);
        mQuoteArrayAdapter.notifyDataSetChanged();
    } else {
        Log.v(OUTER_TAG, "<-- Es sind keine Zitatdaten im Bundle-Objekt vorhanden.");
        Log.v(OUTER_TAG, "<-- Der Zustand konnte nicht wiederhergestellt werden.");
    }
}

Das Wiederherstellen des Activity-Zustands findet in wenigen Schritten statt. In den Zeilen 4 und 5 wird zuerst die Superklassen-Implementierung der onRestoreInstanceState() Methode aufgerufen, wodurch das Android System den Zustand der View-Hierarchie wiederherstellen kann. Anschließend lassen wir eine Log-Meldung ausgeben, die über das Betreten der Methode informiert.

In Zeile 7 wird der JSON-String aus dem Bundle-Objekt, dem Instance State der Activity, ausgelesen. Auf den JSON-String, der die Einträge des ListViews enthält, wird mit Hilfe des Schlüssels LISTVIEW_DATA zugegriffen, welcher der getString() Methode übergeben wird.

Mit der if-Anweisung in Zeile 9 prüfen wir, ob der JSON-String auch aus dem Bundle-Objekt ausgelesen werden konnte. Ist dies der Fall, lassen wir ihn in eine Quote-Liste umwandeln. Dies geschieht in Zeile 10 mit Hilfe der createQuotesFromJSONString( Methode, einer weitere Hilfsmethode der Utility-Klasse, die JSON-Daten auslesen und in eine Liste von Quote-Objekten umwandeln kann.

Die aus den JSON-String erzeugte Quote-Liste wird in der Variable restoredQuoteList gespeichert. Diese muss nur noch der Datenquelle unseres ListViews als Datensatz hinzugefügt werden. Dies wird in den Zeilen 11 und 12 durchgeführt, indem die Datenquelle zuerst geleert und anschließend mit der erzeugte Quote-Liste gefüllt wird.

Damit unser ListView die neuen Daten auch auf dem Bildschirm ausgibt, müssen wir ihn über das Ändern des Datensatzes informieren. Dies geschieht in Zeile 13 mit Hilfe der Methode notifyDataSetChanged(), die auf der Instanz des ListView-Adapters aufgerufen wird. Der ListView wird daraufhin mit den wiederhergestellten Einträge neu gezeichnet.

Sollte der JSON-String nicht aus dem Bundle-Objekt ausgelesen werden können, wird der else-Zweig betreten und in den Zeilen 15 und 16 zwei Log-Meldungen auf der Konsole ausgeben, welche über die fehlenden Zitatdaten im Bundle-Objekt und das Scheitern der Zustands-Wiederherstellung informieren.

Mit diesen Quellcodezeilen haben wir die Methoden onSaveInstanceState() und onRestoreInstanceState() implementiert. Sie werden von nun an den Zustand unserer MainActivity speichern und wiederherstellen, wenn die Activity aufgrund von Systembeschränkungen vom Android System zerstört werden musste.

In Android Studio sollte der Inhalt der 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 MainActivity.java Klassendatei dargestellt. Es sind nur die beiden hinzugefügten Methoden aufgeklappt. Alle anderen Methoden sind unverändert geblieben und daher zugeklappt. Die hinzugefügten Codezeilen sind zudem mit Markierungen versehen worden.

Welche Bedeutung die jeweilige Zeile bzw. der jeweilige Code-Block besitzt, ist in der unteren Liste angegeben:

  1. A – Die Konstanten LISTVIEW_DATA enthält als Wert den Schlüssel, unter dem die Zustandsdaten abgelegt werden.
  2. B – Die onSaveInstanceState() Methode zum Speichern des Activity-Zustands.
  3. C – Die onRestoreInstanceState() Methode zum Wiederherstellen des Activity-Zustands.

Wir haben nun die Callback-Methoden zum Speichern und Wiederherstellen des Activity-Zustands in unserer MainActivity-Klasse implementiert. Unsere Android App ist nun in der Lage den Zustand ihrer Activity zu konservieren, falls diese aufgrund von Systembeschränkungen vom Android System zerstört werden musste. Dabei werden zwei Log-Meldungen an die Konsole ausgegeben, die über das Betreten der jeweiligen Callback-Methode informieren.

Als Nächstes möchten wir unsere Implementierung testen und analysieren, wie unsere Android App den Zustand ihrer Activity zur Laufzeit speichert und wiederherstellt. Dazu werden wir sie auf einem Android Virtual Device im Emulator ausführen lassen.

4. 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 den Zustand der Activity speichert und wiederherstellt.

android_activity_lifecycle_new

Die Callback-Methoden des Activity Lifecycles in Android

In der rechten Abbildung ist der Android Activity Lifecycle ab Android 9.0 dargestellt. Darin ist zu erkennen, dass die Callback-Methoden zum Speichern und Wiederherstellen des Activity-Zustands nur in bestimmten Situationen aufgerufen werden.

Die onSaveInstanceState() Methode wird nur vom Android System aufgerufen, wenn die Activity aufgrund von Systembeschränkungen zerstört werden musste.

Dies ist etwa der Fall, wenn zu wenig Speicher im System vorhanden ist und daraufhin gestoppte Activities zerstört werden müssen. Oder wenn ein Configuration Change Ereignis eingetreten ist, z.B. wenn das Android Gerät rotiert wurde und sich dadurch die Orientierung des Bildschirms geändert hat.

Nur wenn das Android System die onSaveInstanceState() Methode aufruft, kann das Bundle-Objekt, das den Instance State in sich als Sammlung von Schlüssel-Wert Paaren enthält, erzeugt und der Zustand der Activity darin konserviert werden.

Ob das Bundle-Objekt vor dem Zerstören der Activity erzeugt werden konnte, wirkt sich auf den Ablauf, nach dem die zerstörte Activity von Neuem erstellt wird, aus.

Nur wenn das Bundle-Objekt vor dem Zerstören erzeugt wurde, kann der Activity-Zustand wiederhergestellt werden. Daher ruft das Android System die onRestoreInstanceState() Methode nur auf, wenn das Bundle-Objekt ungleich null ist.

Zudem bleibt festzuhalten, dass der genaue Zeitpunkt an dem die onSaveInstanceState() Methode vom Android System aufgerufen wird, von der auf dem Gerät installierten Android Version abhängt. Ab der Version Android 9.0 erfolgt der Aufruf nach der onStop() Methode, so wie in der Abbildung dargestellt. In früheren Android Versionen erfolgt der Aufruf jedoch vor der onStop() Methode. Er kann dann sogar vor der onPause() Methode erfolgen.

Diese Problematik werden wir gleich in der Praxis noch genauer kennenlernen, wenn wir unserer App auf dem Android Virtual Device im Emulator ausführen werden.

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

4.1 Testen unserer Implementierung durch Rotieren des Bildschirms

Sobald unsere App auf dem AVD ausgeführt wird, können wir das Speichern und Wiederherstellen des Activity-Zustands überprüfen.

Dazu führen wir eine Drehung des Bildschirms aus, wodurch ein Orientation Configuration Change Ereignis eintritt und das Android System die Activity zerstört und anschließend wieder neu erstellt. Dabei wird die onSaveInstanceState() Methode zum Speichern und die onRestoreInstanceState() Methode zum Wiederherstellen des Activity-Zustands aufgerufen werden.

Diesen Vorgang können wir im Logcat Tool Window von Android Studio verfolgen, da beide Callback-Methoden eine kurze Log-Meldung an die Konsole ausgeben, sobald sie vom Android System aufgerufen werden.

Die Log-Meldungen können wir im Logcat Tool Window 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.
save_instance_state_log_1

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 führen wir eine Bildschirmrotation durch, wodurch die MainActivity vom Android System aufgrund eines Orientation Configuration Change zerstört und sofort wiederhergestellt wird.

Hinweis: Mit dem Bedienfeld auf der rechten Seite des Android Emulators können Bildschirmrotationen sehr einfach ausgeführt werden. Mit Hilfe der beiden Buttons Rotate left und Rotate right lässt sich das virtuelle Android Gerät um 90 Grad gegen und mit dem Uhrzeigersinn drehen.

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

save_instance_state_log_2

Die MainActivity wurde aufgrund der Bildschirmrotation vom Android System zerstört und wiederhergestellt

Das Android System muss die MainActivity zerstören, damit sie sich an die neue Konfiguration durch Laden alternativer Ressourcen anpassen kann. Dazu ruft es die onPause() und onStop() Methoden auf. Danach erfolgt der Aufruf der onSaveInstanceState() Methode, in welcher wir den Zustand der Activity speichern lassen. Erst danach wird die Activity durch die onDestroy() Methode zerstört.

Hinweis: Vor Android 9.0 kann der Aufruf der onSaveInstanceState() Methode bereits nach der onPause() Methode erfolgen.

Sofort nachdem die Activity zerstört wurde, ruft das Android System die onCreate() und onStart() Methoden auf. Die Activity wird wieder neu erzeugt. Ihren vorherigen Zustand könnte man jetzt schon in der onCreate() Methode wiederherstellen, da dieser auch das Bundle-Objekt mit dem gespeicherten Instance State übergeben wird.

Wir führen das Wiederherstellen des Activity-Zustands aber in der onRestoreInstanceState() Methode durch, welche unmittelbar nach der onStart() Methode aufgerufen wird. Dies ist aber nur der Fall, wenn das Bundle-Objekt existiert. Ist das Bundle-Objekt null, wird die Methode nicht vom Android System aufgerufen.

Nachdem der Activity-Zustand wiederhergestellt wurde, ruft das Android System die onResume() Methode auf und die Activity betritt den Resumed State. Sie besitzt nun wieder den Benutzer-Fokus und befindet sich vollständig im Bildschirmvordergrund. Alle ihre Eigenschaften konnten mit Hilfe des Bundle-Objekts wiederhergestellt werden.

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:

save_instance_state_log_3

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. Aus diesem Grund wurde die onSaveInstanceState() Methode auch nicht aufgerufen und auch kein Bundle-Objekt erzeugt.

4.2 Testen unserer Implementierung durch Stoppen der MainActivity

Als Nächstes möchten wir untersuchen, was passiert, wenn die Activity in den Hintergrund rückt und dadurch den Stopped State betritt. Dazu starten wir unsere Android App erneut auf dem Android Virtual Device im Emulator. Auch diesmal wollen wir die von unserer Anwendung ausgegebenen Log-Meldungen in Android Studio analysieren.

Zum Betrachten der Log-Meldungen im Logcat Tool Window verwenden wir die selben Einstellungen:

  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.
restart_log_1aa

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:

restart_log_2aa

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.

Obwohl die Instanz der Activity noch vollständig intakt im Speicher liegt, ruft das Android System die onSaveInstanceState() Methode und lässt den Zustand der Activity zusätzlich speichern. Der Aufruf erfolgt in unserem Fall nach der onStop() Methode.

Das Android System ruft die onSaveInstanceState() Methode auf, um sicherzustellen, das der Activity-Zustand erhalten bleibt, sollte das Android System die Activity aufgrund von Speichermangel aus dem Stopped State heraus zerstören müssen.

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:

restart_log_3aa

Unsere App wurde erneut geöffnet. Dadurch wurde die Activity wieder fortgesetzt. Ihr Zustand blieb dabei erhalten und musste nicht wiederhergestellt werden.

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.

Aus diesem Grund wurde die onRestoreInstanceState() Methode auch nicht vom Android System aufgerufen, obwohl vorher beim Überführen der Activity in den Stopped State ihr Zustand im Bundle-Objekt abgespeichert worden ist.

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:

restart_log_4aa

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 die Activity nicht mehr länger benötigt. Daher wurde die onSaveInstanceState() Methode auch nicht aufgerufen.

Zusammenfassung

In dieser Lektion haben wir die beiden Callback-Methoden onSaveInstanceState() und onRestoreInstanceState() kennengelernt. Sie sind Bestandteil des Android Activity Lifecycles und werden vom Android System für das Speichern und Wiederherstellen des Activity-Zustands verwendet.

In der onSaveInstanceState() Methode haben wir den Inhalt des ListViews, also die Elemente seiner Datenquelle, ausgelesen und in einem Bundle-Objekt abgelegt. In der onRestoreInstanceState() Methode haben wir aus diesem Bundle-Objekt die gespeicherten Daten wieder ausgelesen und mit ihnen die Datenquelle unseres ListViews befüllt.

Auf diese Weise werden die ListView-Einträge wiederhergestellt, wenn die MainActivity vom Android System aufgrund von Systembeschränkungen zerstört werden muss. Wann dies genau der Fall ist, haben wir im theoretischen Teil dieser Lektion ausführlich behandeln. Dabei haben wir erfahren, welche Zustandsinformationen der Activity das Android System automatisch speichert und welche von uns manuell gesichert werden müssen.

Im praktischen Teil dieser Lektion haben wir zunächst die Hilfsmethode createJSONStringFromQuoteList() in der Hilfsklasse Utility implementiert. Sie ist für das Umwandeln einer Quote-Liste in einen JSON-String verantwortlich. Sie wird für das Speichern des ListView-Inhalts in der onSaveInstanceState() benötigt, da nur bestimmte Datentypen in das Bundle-Objekt abgelegt werden können.

Anschließend haben wir die beiden Methoden onSaveInstanceState() und onRestoreInstanceState() in der MainActivity-Klasse implementiert. Von der onSaveInstanceState() Methode haben wir den Inhalt unseres ListViews auslesen und in Form eines JSON-Strings in einem Bundle-Objekt ablegen lassen, sobald die Activity in den Hintergrund rückt und droht vom Android System zerstört zu werden.

Mit der onRestoreInstanceState() Methode haben wir die gespeicherten Inhalte wieder aus dem Bundle-Objekt auslesen und der ListView-Datenquelle hinzufügen lassen. Auf diese Weise können wir den Zustand der vom Android System zerstörten Activity wieder vollständig herstellen.

Abschließend haben wir unsere Android App im Emulator auf einem Android Virtual Device ausgeführt und überprüft, ob der Zustand der MainActivity korrekt gespeichert und wiederhergestellt wird, falls die Activity zerstört wurde.

In der nächsten Lektion werden wir uns nochmals mit dem Android Activity Lifecycle beschäftigen. Wir werden lernen, wie man den Zustand der MainActivity persistent in einer Datei speichern und wieder aus der Datei auslesen kann. Dabei werden wir auch erfahren, in welcher Lebensphase der Activity das Speichern ihrer Daten erfolgen sollte.

Weiterführende Literatur




Schreibe einen Kommentar

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