Skip to content

Saving View State

Eli Hart edited this page Dec 20, 2017 · 9 revisions

RecyclerView does not support saving the view state of its children the way a normal ViewGroup would. Epoxy adds this missing support by managing the saved state of each view on its own.

Saving view state is useful for cases where the view is modified by the user, such as Carousel scroll position.

Saved state should not overlap with any props applied by the EpoxyModel. For example, a CarouselModel can set what items to show in the carousel, and the saved view state would restore scroll position for those items.

It does not work well to save the view state of an EditText, since EditText automatically saves the text value - this prevents you from setting the text from your model because the saved state will override it.

To prevent saved view state from conflicting with model props like that, make sure that they are completely independent!

Enabling Saved State

Saving state adds extra overhead when binding models, and is disabled by default. You can enable it on a per model basis for the views that require it.

When this is enabled, Epoxy will manually call View#saveHierarchyState to save the state of the view when it is unbound. That state is restored when the view is bound again. This will save the state of the view as it is scrolled off screen and then scrolled back on screen.

State is only restored on a view's initial bind. If the model is updated while the view is still on screen then the model will be rebound to the view (in order to apply the changes), but the saved view state will not be applied again.

To save the state across separate adapter instances you must call onSaveInstanceState on your Epoxy controller (eg in your activity's onSaveInstanceState method), and then restore it with onRestoreInstanceState once the controller is created again. This will preserve the view state when the activity or fragment is recreated.

ModelView Models

Use the saveViewState param in the ModelView annotation

@ModelView(saveViewState = true)

Manually Created Models

Override EpoxyModel#shouldSaveViewState and return true.

Databinding Models

Models generated from databinding layouts cannot currently support saved state. Open an issue if you need support for this.

In Model Groups

If you have a view inside of an EpoxyModelGroup that you would like to save, then the corresponding nested model must have saved state enabled for it.

Additionally, if your xml is set up using view stubs you must set the inflatedId xml attribute on that model's viewstub. For example, in the sample app we have a horizontal recycler nested inside a model group and we want to save the scroll position, so we set an id like so:

<ViewStub
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:inflatedId="@+id/recycler_view" />

Without this the view won't have an id to associate its saved state with.

With multiple RecyclerViews

Saved state does not work properly if you set the same adapter on multiple RecyclerViews. In that case, any model ids that exist in multiple RecyclerViews would cause state for those models to be shared across RecyclerViews.