Manage RecyclerView state

RecyclerView can display large amounts of data using minimal graphical resources. As users scroll through the items in a RecyclerView, View instances of items that have scrolled off screen are reused to create new items as they scroll on screen. But configuration changes, such as device rotation, can reset the state of a RecyclerView, forcing users to again scroll to their previous position in the list of items.

RecyclerView should maintain its state—in particular, scroll position—and the state of its list elements during all configuration changes.

Maintain state

Set the state restoration policy of the RecyclerView.Adapter to save the RecyclerView scroll position. Save the state of RecyclerView list items. Add the state of the list items to the RecyclerView adapter, and restore the state of list items when they're bound to a ViewHolder.

1. Enable Adapter state restoration policy

Enable the state restoration policy of the RecyclerView adapter so that the scrolling position of the RecyclerView is maintained across configuration changes. Add the policy specification to the adapter constructor:

Kotlin

class MyAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    init {
        stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
    }
    ...
}

Java

class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public Adapter() {
        setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY);
    }
    ...
}

2. Save the state of stateful list items

Save the state of complex RecyclerView list items, such as items that contain EditText elements. For example, to save the state of an EditText, add a callback similar to an onClick handler to capture text changes. Within the callback, define what data to save:

Kotlin

input.addTextChangedListener(
    afterTextChanged = { text ->
        text?.let {
            // Save state here.
        }
    }
)

Java

input.addTextChangedListener(new TextWatcher() {

    ...

    @Override
    public void afterTextChanged(Editable s) {
        // Save state here.
    }
});

Declare the callback in your Activity or Fragment. Use a ViewModel to store the state.

3. Add list item state to the Adapter

Add the state of list items to your RecyclerView.Adapter. Pass the item state to the adapter constructor when your host Activity or Fragment is created:

Kotlin

val adapter = MyAdapter(items, viewModel.retrieveState())

Java

MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());

4. Recover list item state in the adapter's ViewHolder

In the RecyclerView.Adapter, when you bind a ViewHolder to an item, restore the item's state:

Kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    ...
    val item = items[position]
    val state = states.firstOrNull { it.item == item }

    if (state != null) {
        holder.restore(state)
    }
}

Java

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    ...
    Item item = items[position];
    Arrays.stream(states).filter(state -> state.item == item)
        .findFirst()
        .ifPresent(state -> holder.restore(state));
}

Key points

Results

Your RecyclerView is now able to restore its scroll position and the state of every item in the RecyclerView list.

Collections that contain this guide

This guide is part of these curated Quick Guide collections that cover broader Android development goals:

Enable your app to support an optimized user experience on tablets, foldables, and ChromeOS devices.

Have questions or feedback

Go to our frequently asked questions page and learn about quick guides or reach out and let us know your thoughts.