The right way to Save state ViewGroup
Firstly, if you want to test save state on android go to
Setting -> Developer options -> Don’t Keep Activities
For making an activity save its state before destroying itself when the … button has been push, so the onRestoreInstanceState( ) will be called when you return to the application.
Problem
From the picture above, we create a ViewGroup consisting of ImageView, EditText and Switch. Basically, we push application to background and come back again, we will notice that “333” which is the last one will be put in every EditText. But it is wrong because we expect “111” “222” and “333” is our expect
Most developer usually ignore this case. Today we will make it right .😎
Before we start
let’s know Save state
This section is consisting of 2 parts; save state for Activity/Fragment and View/ViewGroup.
1. Saved state for Activity/Fragment
From the picture above, onSaveInstanceState( ) will be called every time when you minimize application.
But onRestoreInstanceState( ) will be called “ when ” Activity/Fragment destroyed only. However, we cannot expect that when Activity/Fragment destroyed. Example case: other application use all ram util android framework destroy application on background state
So onRestoreInstanceState( ) will be called or not. It’s the reason why we have to enable Don’t Keep Activites at Developer Options before you test restore state
For Activity/Fragment, we don’t have to fix anything because it just save state itself and call onSaveInstanceState( )/ onRestoreInstanceState( ) of each View/ViewGroup. So, the cause of the problem is the View/ViewGroup which we put into Activity/Fragment
2. Saved state for View/ViewGroup
For View/ViewGroup, Activity/Fragment will call each view to save state itself. Behind the scenes saveHierarchyState( )/restoreHierarchyState( ) of each view will be called and continue to onSaveInstanceState( )/onRestoreInstanceState( ) follow by the picture above.
Cause of the problem
Let’s take a look at the method
void dispatchSaveInstanceState( SparseArray )และvoid dispatchRestoreInstanceState( SparseArray )
The responsibility of this method is saving/restoring state of ChildView that put into each ViewGroup base on viewId and put state into main SparseArray which passed via parameter.
the picture below shows the problem
We will notice that state of each ChildView will be put into main SparseArray cause state is replaced every time. So when you minimize application and come back the last state “333” will show into EditText 😭
This is the serious case, If the last state of EditText is sensitive data such as password it will be shown to another people.
Let’s fix it
The idea about this problem, We have created SpareArray of each ViewGroup to separate state independent and put into main SpareArray to avoid save state are replaced
From the picture, Each EditText receive “111”, “222” and “333” correctly.
Up to now, we cover all main concept. It’s time to get into the code
Firstly, creating one base class and override 2 method
To tell this ViewGroup that don’t autosave/restore the state of each ChildView. because we will do it manually.
Next, we override
void onRestoreInstanceState(Parcelable state)
and create 2 new methods is
Parcelable onSaveInstanceChildState( ChildSavedState ss )andvoid onRestoreInstanceChildState( ChildSavedState ss)
Parcelable onSaveInstanceChildState( ChildSavedState ss )
In this method, we create SparseArray of each ViewGroup to avoid state is replaced and
void onRestoreInstanceChildState( ChildSavedState ss)
In the same way
Finally, we create ChildSavedState inner class for saving state of ChildView
So we create Base class boilerplate for ViewGroup completely.
Example usage
We create SwitchViewGroup class extend BaseViewGroup which already done and override 2 methods.
Let’s see at onSaveInstanceState( ), we call
SavedState ss = (SavedState) onSaveInstanceChildState(
new SavedState( superState )
);
to save state ChildView before. So, “SaveState ss” have state of All ChildView and we continue to save state SwitchViewGroup
and create SavedState inner class that extends ChildSavedState (inner class from BaseViewGroup).
Up to now, we have complete CustomViewGroup.
This is boilerplate example code for CustomViewGroup. You can pull my code to research or do anything that you want.
See you next blog.
Don’t forget to click 👏 below and share to other Android developers 😎