Alles was du über Saved Instance State wissen musst
- 5 Minuten - 893 Wörtersavedinstancewas?
Eine Eigenheit von Android ist, dass bei einer Änderung der View-Konfiguration die komplette View-Hierarchie zerstört und neu aufgebaut wird. Darunter fallen Activities + Fragments + Views und werden im Folgenden nur noch als View bezeichnet.
In 90% der Fälle ist damit das Drehen des Gerätes vom Landscape- in den Portrait-Modus (oder zurück) gemeint. Dies hat den Hintergrund, dass es mit Android möglich ist zwei völlig verschiedene Layouts für Hoch- und Quer-Modus zu definieren. Nach meiner Erfahrung wird dies zwar überwiegend nur bei Tablets verwendet, aber dennoch ist das Feature auch bei Smartphones vorhanden.
Zusätzlich kann die View Hierarchie jederzeit vom System zerstört werden, wenn sich die App im Hintergrund befindet und Android weitere Resourcen benötigt. Dies kann zB ein eingehender Anruf sein oder eine andere App wird aus unserer App heraus aufgerufen (Kamera, Email, etc.). Besonders “Low Budget”- und ältere Geräte sind von diesem sogenannten “process death” betroffen.
Wenn nun unsere Views zerstört werden, was passiert dann mit unseren - sichtbaren und unsichtbaren - Daten? Um diese Daten in die neue Konfiguration zu retten, oder sie beim Zurückkehren nach dem process death wiederherzustellen, hat Android den sogenannten “Saved Instance State”.
Art der Daten
Damit besser deutlich wird für welche Aufgabe der Saved Instance State tatsächlich gebraucht wird, müssen wir erst die Art der Daten definieren die in einem View vorhanden sind:
- übergebene Daten
- viewspezifische Daten
- unsichtbare Daten
Übergebene Daten
Hierbei handelt es sich um Daten die
- vom Aufrufer als
Bundle
(IntentExtras/Arguments) übergeben wurden - für die korrekte Ausführung des Views notwendig sind und
- sich zur Laufzeit eines Views nicht ändern werden. Beispielsweise die ID des ausgewählten Users, für den die Profildaten angezeigt werden sollen.
Diese Daten brauchen wir nicht zu speichern, da sie vom System beim (neu) Erzeugen des Views in Form eines Bundles automatisch erneut mit übergeben werden und auch aus diesem Bundle bezogen werden sollten.
Viewspezifische Daten
Dies sind die Eingabedaten der verwendeten Android-View
s. Um beim Beispiel “Userprofil” zu bleiben: Hier könnte eine Status-Nachricht eingegeben werden oder ein Haken für eine Option gesetzt werden (EditText
oder CheckBox
zB.).
Diese Daten speichert Android automatisch und stellt sie auch wieder her, sofern dem View eine ID zugewiesen wurde - in der Regel passiert dies in der XML-Datei für die Beschreibung des Layouts (android:id
).
Unsichtbare Daten
Hier sind alle Daten gemeint, die dynamisch während der Interaktion mit dem View erzeugt oder geändert werden. Es kann sich hierbei zum Beispiel um die aktuelle Seite bei Paging handeln oder ein temporäres Objekt das durch einen Wizard befüllt wird und noch nicht gespeichert wurde.
Diese Daten müssen mit dem Saved Instance State gesichert werden, da sie sonst nach dem Drehen des Gerätes oder Durchlaufen des process death nicht mehr vorhanden wären.
Speichern
Nachdem wir geklärt haben, welche Daten wir überhaupt speichern sollten, sehen wir uns die konkrete Methode an mit welcher wir die Daten speichern können.
Bevor eine Activity oder ein Fragment zerstört wird ruft Android eine der “Lifecycle”-Methoden auf, um uns die Möglichkeit bereitzustellen unsere Daten zu speichern:
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
}
In dieses Bundle Objekt können nur primitive Datentypen gespeichert werden. Wenn komplexe Klassen gespeichert werden sollen, müssen diese das Java Serializable
Interface oder das Android Parcelable
Interface implementieren.
outState.putInt(STATE_CURRENT_PAGE, currentPage);
Zusätzlich zu den eigenen Daten speichert Android selbst auch Daten in diesem Bundle. Unter anderem die oben genannten “ViewSpezifischen” Daten, aber auch Informationen über vorhandende Fragments oder Activities. Man ist also nicht selbst für die komplette Größe eines Bundles verantwortlich, sondern es kommt eine nicht bekannte Menge an Daten durch das System dazu.
Achtung Es ist zu beachten, dass der Platz im Bundle speichertechnisch beschränkt ist! Die genaue Größe ist nicht offiziell bekannt, aber man geht davon aus dass ab 500KB Daten Exceptions auftreten können. Siehe hierzu auch TransactionTooLargeException
.
Laden
Android wäre nicht Android, wenn wir hierfür nicht mehrere Möglichkeiten zu Verfügung hätten…
public void onCreate(...)
public View onCreateView(...)
public void onViewCreated(...)
public void onViewStateRestored(...)
...
Es gibt hier keine pauschal “richtige” oder “falsche” Stelle um die Daten wiederherzustellen sondern hängt immer vom konkreten Anwendungsfall ab. Die Variablen sollten natürlich korrekt wiederhergestellt sein, bevor das erste Mal auf sie zugegriffen wird ;-)
Jede dieser Methoden bekommt vom System wieder das gleiche Datenpaket in Form der Bundle-Klasse übergeben, aus welchem die gespeicherten Variablen dann angefordert werden können:
currentPage = savedState.getInt(STATE_CURRENT_PAGE);
Zu beachten ist, dass nicht zwingend alle Methoden sofort ausgeführt werden - zB. wenn das Fragment nach einer Konfigurationsänderung zwar im FragmentManager enthalten ist, aber nicht angezeigt wird. In dem Fall wird zwar onCreate() bereits aufgerufen, die anderen Methoden aber ggf. erst wenn das Fragment wirklich angezeigt wird. Hier können fiese Bugs auftreten die schwer zu finden sind. Als wäre das nicht schon kompliziert genug, hängt es zusätzlich noch von der Version der androidx
Library oder der auf dem Gerät laufenden Android-Version ab…
Zusammengefasst
- Daten die der Activity oder dem Fragment (setExtra/setArguments) übergeben wurden und im View nicht änderbar sind, brauchen nicht über den savedInstanceState gespeichert/geladen werden. Diese Daten können und sollten nach dem Neuerstellen wieder aus dem Bundle geladen und nicht noch extra gespeichert werden.
- Daten die in den Standard-Android View-Elementen (EditText, Checkbox) eingegeben wurden, brauchen nicht gespeichert werden wenn den entsprechenden View-Elementen eine ID zugewiesen wurde.
- Daten die im View verändert oder erzeugt werden und nicht in die ersten beiden Kategorien gehören, müssen zwingend per Saved Instance State in die neue Konfiguration oder den neuen Prozess gerettet werden.