Deep dive into android restoration - DroidCon Paris 2014

92
Deep Dive Into Android State Restoration

description

http://fr.droidcon.com/2014/agenda/ http://fr.droidcon.com/2014/agenda/detail?title=Deep+Dive+Into+State+Restoration Come learn about how Android saves state in general in order to be able to restore an application in the exact same state the process was prior being killed because of a low memory condition or a configuration change. In this talk we will mainly focus on the Parcelable and Parcel objects and how Android uses them to save/restore some important stateful information such as the complete UI state. Speaker : Cyril Mottier, Capitaine Train Cyril Mottier is Mobile Software Engineer at Capitaine Train and Android Google Developer Expert. Passionate about technology and design, Cyril is an avid lover of Android and a multi-skilled engineer. He is actively involved in the Android community and shares his passion writing blog posts, creating open source librairies and giving talks. His motto: “Do less, but do it insanely great”

Transcript of Deep dive into android restoration - DroidCon Paris 2014

Page 1: Deep dive into android restoration - DroidCon Paris 2014

Deep Dive Into Android State Restoration

Page 2: Deep dive into android restoration - DroidCon Paris 2014

TWITTER

@cyrilmottier !WEBSITE

cyrilmottier.com

Page 3: Deep dive into android restoration - DroidCon Paris 2014
Page 4: Deep dive into android restoration - DroidCon Paris 2014
Page 5: Deep dive into android restoration - DroidCon Paris 2014
Page 6: Deep dive into android restoration - DroidCon Paris 2014
Page 7: Deep dive into android restoration - DroidCon Paris 2014

The story of a newbie Android developer

Page 8: Deep dive into android restoration - DroidCon Paris 2014

Kevin has just developed his first

Android app

Page 9: Deep dive into android restoration - DroidCon Paris 2014

He discovers an annoying bug: Fields are cleared on rotate

Page 10: Deep dive into android restoration - DroidCon Paris 2014

3 options

Page 11: Deep dive into android restoration - DroidCon Paris 2014

3 optionsDon’t care

Page 12: Deep dive into android restoration - DroidCon Paris 2014

3 optionsDon’t care Block orientation

Page 13: Deep dive into android restoration - DroidCon Paris 2014

3 optionsDon’t care Block orientation Use configChanges

Hint: all options are

Page 14: Deep dive into android restoration - DroidCon Paris 2014

1 <activity!2 android:name=".HomeActivity"!3 android:configChanges="orientation">!4 !5 <!-- Some sweet IntentFilters. -->!6 !7 </activity>

Page 15: Deep dive into android restoration - DroidCon Paris 2014

Kevin’s satisfied

Page 16: Deep dive into android restoration - DroidCon Paris 2014

Still having issues on…

Page 17: Deep dive into android restoration - DroidCon Paris 2014

language changesStill having issues on…

Page 18: Deep dive into android restoration - DroidCon Paris 2014

1 <activity!2 android:name=".HomeActivity"!3 android:configChanges="orientation!4 !5 <!-- Some annoying IntentFilters. -->!6 !7 </activity>

|locale">

Page 19: Deep dive into android restoration - DroidCon Paris 2014

ANGRY!Angry Kevin is

Page 20: Deep dive into android restoration - DroidCon Paris 2014

1 <activity!2 android:name=".HomeActivity"!3 android:configChanges=“orientation|locale|! mcc|mnc|touchscreen|keyboard|! keyboardHidden|navigation|uiMode|! screenLayout|fontScale|screenSize|! smallestScreenSize">!4 !5 <!-- Some fuc**** IntentFilters. Arrggh! -->!6 !7 </activity>

Page 21: Deep dive into android restoration - DroidCon Paris 2014

The nightmare continues… Still having issues when moving the app to the background

Page 22: Deep dive into android restoration - DroidCon Paris 2014

God save the

STATE

Page 23: Deep dive into android restoration - DroidCon Paris 2014

State restoration key components

Page 24: Deep dive into android restoration - DroidCon Paris 2014

The container Parcel

Page 25: Deep dive into android restoration - DroidCon Paris 2014

Parcelable

The container Parcel

The content

Primitives typesPrimitives arrays

Page 26: Deep dive into android restoration - DroidCon Paris 2014

The content

Primitives typesPrimitives arrays

1 parcel.writeInt(1);!2 parcel.writeLong(2L);!3 parcel.writeFloat(3F);!4 parcel.writeString("Hi!");

Parcelable

Page 27: Deep dive into android restoration - DroidCon Paris 2014

1 parcel.writeIntArray(new int[]{1, 2, 3});!2 parcel.writeLongArray(new long[]{1L, 2L, 3L});!3 parcel.writeDoubleArray(new double[]{1, 2, 3});!4 parcel.writeStringArray(new String[]{!5 "Hi", "Droidcon", "guys!"!6 });

The content

Primitives typesPrimitives arrays

Parcelable

Page 28: Deep dive into android restoration - DroidCon Paris 2014

1 public final class Suggestion implements Parcelable {! 2 ! 3 public final String id;! 4 public final String name;! 5 public final int type;! 6 ! 7 public Suggestion(String id, String name, int type) {! 8 this.id = Objects.requireNonNull(id);! 9 this.name = Objects.requireNonNull(name);!10 this.type = type;!11 }!12 !13 }

Page 29: Deep dive into android restoration - DroidCon Paris 2014

1 @Override! 2 public int describeContents() {! 3 return 0;! 4 }! 5 ! 6 @Override! 7 public void writeToParcel(Parcel dest, int flags) {! 8 dest.writeString(id);! 9 dest.writeString(name);!10 dest.writeInt(type);!11 }!12 13 public static final Parcelable.Creator<Suggestion> CREATOR = !14 new Parcelable.Creator<Suggestion>() {!15 public Suggestion createFromParcel(Parcel in) {!16 return new Suggestion(in.readString(), // !17 in.readString(), //!18 in.readInt());!19 }!20 !21 public Suggestion[] newArray(int size) {!22 return new Suggestion[size];!23 }!24 };

Page 30: Deep dive into android restoration - DroidCon Paris 2014

Parcelable.Creator!The base creator interface

!

Parcelable.ClassLoaderCreator!A creator with the ClassLoader passed on read.

!

ParcelableCompat & ParcelableCompatCreatorCallbacks!Compatibility stuff

Page 31: Deep dive into android restoration - DroidCon Paris 2014

Bundle A key-value map & type-safe Parcelable

Page 32: Deep dive into android restoration - DroidCon Paris 2014

Parcel!internally uses reflection

(required to get the CREATOR instance)

…i.e. beware Proguard

Page 33: Deep dive into android restoration - DroidCon Paris 2014

Activity level state restoration

Page 34: Deep dive into android restoration - DroidCon Paris 2014

onCreate(null)

Page 35: Deep dive into android restoration - DroidCon Paris 2014

onCreate(null)

Page 36: Deep dive into android restoration - DroidCon Paris 2014

: non-null Bundle

onSaveInstanceState( )

onCreate(null)

Page 37: Deep dive into android restoration - DroidCon Paris 2014

onSaveInstanceState( )

onCreate( )

onCreate(null)

: non-null Bundle

Page 38: Deep dive into android restoration - DroidCon Paris 2014

onSaveInstanceState( )

onCreate( )

onRestoreInstanceState( )

onCreate(null)

: non-null Bundle

Page 39: Deep dive into android restoration - DroidCon Paris 2014

onSaveInstanceState( )

onCreate( )

onRestoreInstanceState( )

onCreate(null)

: non-null Bundle

Page 40: Deep dive into android restoration - DroidCon Paris 2014

onSaveInstanceState( )

onCreate( )

onRestoreInstanceState( )

onCreate(null)

: non-null Bundle

Page 41: Deep dive into android restoration - DroidCon Paris 2014

What to save?Non persistent or non reconstructible info

Page 42: Deep dive into android restoration - DroidCon Paris 2014

1 public class SearchActivity extends Activity {! 2 ! 3 private static final String STATE_OUTWARD = "state:outward";! 4 ! 5 private DateComponents mOutward;! 6 ! 7 @Override! 8 protected void onCreate(Bundle inState) {! 9 super.onCreate(inState);!10 !11 if (inState != null) {!12 DateComponents components = inState.getParcelable(STATE_OUTWARD);!13 if (components != null) {!14 setOutward(components);!15 }!16 }!17 }!18 !19 @Override!20 protected void onSaveInstanceState(Bundle outState) {!21 super.onSaveInstanceState(outState);!22 outState.putParcelable(STATE_OUTWARD, mOutward);!23 }!24 }

Page 43: Deep dive into android restoration - DroidCon Paris 2014

onSaveInstanceState savesWindow

Page 44: Deep dive into android restoration - DroidCon Paris 2014

Window Fragments

onSaveInstanceState saves

Page 45: Deep dive into android restoration - DroidCon Paris 2014

Window Fragments Dialogs

onSaveInstanceState saves

Page 46: Deep dive into android restoration - DroidCon Paris 2014

Always call the SUPER METHODS Android has no guards on save-related methods

Page 47: Deep dive into android restoration - DroidCon Paris 2014

android:stateNotNeededFor restart-on-crash apps only

(i.e. launcher app)

Page 48: Deep dive into android restoration - DroidCon Paris 2014

Developer options Don’t keep activities

Page 49: Deep dive into android restoration - DroidCon Paris 2014

Developer options Don’t keep activities

Page 50: Deep dive into android restoration - DroidCon Paris 2014

View level state restoration

Page 51: Deep dive into android restoration - DroidCon Paris 2014

Android saves UI state AUTOMAGICALLY

Page 52: Deep dive into android restoration - DroidCon Paris 2014

Android saves UI state AUTOMAGICALLY

(aka “It just works!™”)

Page 53: Deep dive into android restoration - DroidCon Paris 2014

Android saves UI state AUTOMAGICALLY

(aka “It just works!™”)

…except in some cases

Page 54: Deep dive into android restoration - DroidCon Paris 2014

Works out-of-the-box if Views

1. Have an ID

2. Are “save” enabled

3. Come from the framework

Page 55: Deep dive into android restoration - DroidCon Paris 2014

saveHierarchyState()It always begins with a call to

Page 56: Deep dive into android restoration - DroidCon Paris 2014

EditText!@id/text

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

Page 57: Deep dive into android restoration - DroidCon Paris 2014

EditText!@id/text

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

SparseArray<Parcelable>

Page 58: Deep dive into android restoration - DroidCon Paris 2014

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

SparseArray<Parcelable>

S1

EditText!@id/text

Page 59: Deep dive into android restoration - DroidCon Paris 2014

@id/container

SparseArray<Parcelable>

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

S1

EditText!@id/text

Page 60: Deep dive into android restoration - DroidCon Paris 2014

EditText!@id/text

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

@id/container S1

S2 SparseArray<Parcelable>

Page 61: Deep dive into android restoration - DroidCon Paris 2014

@id/text

@id/container S1

S2

SparseArray<Parcelable>

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

EditText!@id/text

Page 62: Deep dive into android restoration - DroidCon Paris 2014

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView@id/text

@id/container S1

S2

SparseArray<Parcelable>

S3

EditText!@id/text

Page 63: Deep dive into android restoration - DroidCon Paris 2014

@id/text

@id/container

@id/check_box

S1

S2

S3

SparseArray<Parcelable>

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

EditText!@id/text

Page 64: Deep dive into android restoration - DroidCon Paris 2014

Controlling save

setSaveEnabled(boolean)

setSaveFromParentEnabled(boolean)

Page 65: Deep dive into android restoration - DroidCon Paris 2014

restoreHierarchyState()It always ends with a call to

Page 66: Deep dive into android restoration - DroidCon Paris 2014

@id/container S1

@id/text S2

@id/check_box S3

SparseArray<Parcelable>

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

EditText!@id/text

Page 67: Deep dive into android restoration - DroidCon Paris 2014

@id/container S1

S2

S3

@id/text

@id/check_box

SparseArray<Parcelable>

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

EditText!@id/text

Page 68: Deep dive into android restoration - DroidCon Paris 2014

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

@id/container S1

S2

@id/check_box S3S1

@id/text

SparseArray<Parcelable>

EditText!@id/text

Page 69: Deep dive into android restoration - DroidCon Paris 2014

@id/container S1

@id/text S2

@id/check_box S3

SparseArray<Parcelable>

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

EditText!@id/text

Page 70: Deep dive into android restoration - DroidCon Paris 2014

EditText!@id/text

RelativeLayout!@id/container

CheckBox!@id/check_box

TextViewS2

@id/container S1

@id/text

@id/check_box S3

S2 SparseArray<Parcelable>

Page 71: Deep dive into android restoration - DroidCon Paris 2014

@id/container S1

@id/text S2

@id/check_box S3

SparseArray<Parcelable>

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

EditText!@id/text

Page 72: Deep dive into android restoration - DroidCon Paris 2014

RelativeLayout!@id/container

CheckBox!@id/check_box

TextView

@id/container S1

@id/text S2

@id/check_box S3

S3

SparseArray<Parcelable>

EditText!@id/text

Page 73: Deep dive into android restoration - DroidCon Paris 2014

Ensure your Views’ IDs are unique & constant

Page 74: Deep dive into android restoration - DroidCon Paris 2014

1 static class SavedState extends BaseSavedState {! 2 int checked;! 3 ! 4 SavedState(Parcelable superState) { super(superState); }! 5 ! 6 private SavedState(Parcel in) {! 7 super(in);! 8 checked = in.readInt();! 9 }!10 !11 @Override!12 public void writeToParcel(Parcel out, int flags) {!13 super.writeToParcel(out, flags);!14 out.writeInt(checked);!15 }!16 !17 public static final Parcelable.Creator<SavedState> CREATOR = !18 new Parcelable.Creator<SavedState>() {!19 public SavedState createFromParcel(Parcel in) {!20 return new SavedState(in);!21 }!22 public SavedState[] newArray(int size) {!23 return new SavedState[size];!24 }!25 };!26 }

Page 75: Deep dive into android restoration - DroidCon Paris 2014

1 @Override! 2 public Parcelable onSaveInstanceState() {! 3 final Parcelable superState = super.onSaveInstanceState();! 4 SavedState ss = new SavedState(superState);! 5 ss.checked = isChecked() ? 1 : 0;! 6 return ss;! 7 }! 8 ! 9 @Override!10 public void onRestoreInstanceState(Parcelable state) {!11 SavedState ss = (SavedState) state;!12 super.onRestoreInstanceState(ss.getSuperState());!13 setChecked(ss.checked == 1);!14 }

Page 76: Deep dive into android restoration - DroidCon Paris 2014

FrameLayout!@id/root

ImageBox!@id/container1

CheckBox!@id/check_box

ImageView!@id/image

ImageBox!@id/container2

CheckBox!@id/check_box

ImageView!@id/image

Page 77: Deep dive into android restoration - DroidCon Paris 2014

FrameLayout!@id/root

ImageBox!@id/container1

ImageView!@id/image

CheckBox!@id/check_box

ImageBox!@id/container2

ImageView!@id/image

CheckBox!@id/check_box

Custom views with children with same IDs

Page 78: Deep dive into android restoration - DroidCon Paris 2014

1 static class SavedState extends BaseSavedState {! 2 ! 3 SparseArray childrenStates;! 4 ! 5 SavedState(Parcelable superState) { super(superState); }! 6 ! 7 private SavedState(Parcel in, ClassLoader loader) {! 8 super(in);! 9 childrenStates = in.readSparseArray(loader);!10 }!11 !12 @Override!13 public void writeToParcel(Parcel out, int flags) {!14 super.writeToParcel(out, flags);!15 out.writeSparseArray(childrenStates);!16 }!17 !18 public static final Creator<SavedState> CREATOR = ParcelableCompat.!19 newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {!20 @Override!21 public SavedState createFromParcel(Parcel source, ClassLoader loader) {!22 return new SavedState(source, loader);!23 }!24 @Override!25 public SavedState[] newArray(int size) {!26 return new SavedState[size];!27 }!28 });!29 }

Page 79: Deep dive into android restoration - DroidCon Paris 2014

1 @Override! 2 public Parcelable onSaveInstanceState() {! 3 final Parcelable superState = super.onSaveInstanceState();! 4 SavedState ss = new SavedState(superState);! 5 ss.childrenStates = new SparseArray<Parcelable>();! 6 for (int i = 0; i < getChildCount(); i++) {! 7 getChildAt(i).saveHierarchyState(ss.childrenStates);! 8 }! 9 return ss;!10 }!11 !12 @Override!13 public void onRestoreInstanceState(Parcelable state) {!14 SavedState ss = (SavedState) state;!15 super.onRestoreInstanceState(ss.getSuperState());!16 for (int i = 0; i < getChildCount(); i++) {!17 getChildAt(i).restoreHierarchyState(ss.childrenStates);!18 }!19 }

Page 80: Deep dive into android restoration - DroidCon Paris 2014

That has solved nothing! Still need to block save/restore dispatch

Page 81: Deep dive into android restoration - DroidCon Paris 2014

1 @Override!2 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {!3 dispatchFreezeSelfOnly(container);!4 }!5 !6 @Override!7 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {!8 dispatchThawSelfOnly(container);!9 }

Page 82: Deep dive into android restoration - DroidCon Paris 2014

Fragment level state restoration

Page 83: Deep dive into android restoration - DroidCon Paris 2014

Very similar to Activities state restoration lifecycle.

(Fragments are tied to Activity after all)

Page 84: Deep dive into android restoration - DroidCon Paris 2014

Fragment blocks Activity save mechanism

with framework setSaveFromParentEnabled(false)

with support library NoSaveStateFrameLayout

Page 85: Deep dive into android restoration - DroidCon Paris 2014

2 distinct states

Fragment + View common case

View only detach, addToBackStack, etc.

Page 86: Deep dive into android restoration - DroidCon Paris 2014

Can to be used to create smooth transitions between your Activities:

!

- Save the state SA of A - Start B with no animations passing SA

- Apply SA to B - Transition between A and B was smooth

Leveraging save/restore

Page 87: Deep dive into android restoration - DroidCon Paris 2014

Summarizing in three rules

Page 88: Deep dive into android restoration - DroidCon Paris 2014

Always save the state An Android app must survive configuration changes & low memory conditions.

Page 89: Deep dive into android restoration - DroidCon Paris 2014

Only save essential info Only save info that is non persistent

or can not be reconstructed later.

Page 90: Deep dive into android restoration - DroidCon Paris 2014

Use correct levels Save instance states at the appropriate component level: Activity, Fragment or View.

Page 91: Deep dive into android restoration - DroidCon Paris 2014

Thank you! @cyrilmottier

cyrilmottier.com

Page 92: Deep dive into android restoration - DroidCon Paris 2014

Resources Dressed for Iceland • Cécile Bernard Moelwynion, Eryri, Cymru • Marc Poppleton Happy, Confused, Wink, Sad, Angry • Megan Sheehan Floppy-Disk • Alex Auda Samora

Fonts Source Sans Pro

Courier