Persisting view-state when using a custom backstack: Creating a Flow-like custom backstack (Part 4)

We’ve been creating a backstack for 3 parts now, and have solved a few problems:
- In Part 1, we’ve created a basic backstack that allowed state changes and exposed 3 convenient operators to manipulate the history list
- In Part 2, we’ve managed to provide parameters to our custom viewgroups
- In Part 3, we’ve made our backstack able to enqueue state changes while a state changer is not available, or a state change is already in progress
But we need to be able to persist the view state so that views that are removed still preserve their state, and we must also make sure we can restore this even across process death.
If you check the good ol’ Flow this example is influenced by, it did not use to have a KeyManager class, it did not have any means of persisting view state with the library.
So we’re not gonna add it to the library yet either, we’ll just add it to the example.
— — — — — — — — — — — — — — — — — — — — —
Persisting the viewstate
Actually, I can just show the commit that adds view-state persistence to our Activity, and explain afterwards. Look!

So what can we see here?
Saving the view hierarchy state
In order to save the state of our view hierarchy, there is a convenient method called view.saveVierarchyState(SparseArray<Parcelable>)
.
We can store this as a Parcelable, along with a few other things; and we need this to be identifiable.
The State class
We added a State
class for storing our viewstate, and it stores 3 things:
- the
Key
of the given view (to identify this state later when we restore it) - the
SparseArray<Parcelable>
that is the saved view hierarchy state - a
Bundle
in case we want to add additional data to our stored state.
The State
is Parcelable
so that we can persist it to Bundle in the form of ArrayList<Parcelable>
, just like we do with keys (which represent the application state).
Keeping track of the State
In order to keep track of the state, we store it in a Map
that binds it to our Key
( so it is Map<Key, State>
).
We create a new entry in this map during the state changer callback (to preserve the previous view’s state, the one that we swap out and remove), and in onSaveInstanceState()
(to preserve the current view’s state).
Removing States that are no longer needed
When a state change occurs, we clear out the states we no longer need using keySet.retainAll()
.
Restoring State after process death/config change
And when our Activity is restored, we also restore the keyStateMap
as well from the savedInstanceState
Bundle.
Conclusion
With that, it actually works!
Now that we have solved the problem of saving our state, we’ve solved our most aching problems.
But we still have some pain points:
- we don’t have convenient lifecycle callbacks to our views for when they get created, and removed (or destroyed) ~ although maybe we could use square/coordinators for that
- you need to add a bunch of code in your Activity to integrate the backstack, and the application state/view state persistence. Maybe we could move this code out, into the library?
In the meantime, the current source code is available here.