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

Fault ViewGroup savedstate

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.

Restore state to ViewGroup correctly.

This is boilerplate example code for CustomViewGroup. You can pull my code to research or do anything that you want.

See you next blog.

follow me at https://www.facebook.com/thekhaeng.io/

Don’t forget to click 👏 below and share to other Android developers 😎

--

--

Nonthawit 👨🏻‍🚀 (น้ำแข็ง)
Nextzy

Tech CEO & Co-founder of The Existing Company┃Software Engineer┃Designer ┃Product Coach ┃Public Speaker ┃ Blogger┃Notion Expert