Updates that I ignored

Androidx recyclerview 1.2.0-alpha02 adds a new feature called MergeAdapter to help developers add headers and footers to recyclerview more easily. Use the official API to add headers and footers to Recyclerview

There is also a change in recyclerView. Adapter lazy State Restoration to help developers restore RecyclerView

recyclerview update

I don’t really feel that way about this feature. As we all know, views in Android have internal methods for state saving and recovery. The same is true of RecyclerView, which can restore its scrolling position

View Restores the internal status

For more information about state saving, see AndroidX SaveState ViewModel-SavEstate analysis

This is also true

RecyclerView can restore the scrolling position inside

serendipity

Recently I saw Florina Muntenescu’s Restore RecyclerView Scroll Position, which introduced “RecyclerView.Adapter lazy State Restoration”. That piqued my interest

serendipity

As described in the article, RecyclerView loses its scrolling position during activity/fragment reconstruction because the data in the Adapter is “asynchronous” loaded, and the data in RecyclerView layout is not loaded. Therefore, it cannot restore the previous position state. A relatively simple example is the use of Navigation component for Navigation. When returning, RecyclerView in the fragment loses its sliding position because it calls the interface again to obtain data

Lazily loading data, unable to restore scroll position

The solution

There are several ways to ensure that RecyclerView is restored to the correct scrolling position. The best way to do this is to use a cache, a ViewModel or Repository to cache the data to be displayed. Make sure that the data is always set on Adapter before the first layout is passed in. There are other solutions, too, that are either too complicated or not elegant enough

Recyclerview: The solution in 1.2.0-Alpha02 is to provide a new Adapter method that allows setting state recovery policies with three options

  • ALLOW
  • PREVENT_WHEN_EMPTY
  • PREVENT

ALLOW

This is the “default” state and it will immediately restore RecyclerView. This policy does not allow lazy loading of data, use PREVENT_WHEN_EMPTY

PREVENT_WHEN_EMPTY

The RecyclerView state is restored only when Adapter is not empty (adapter.getitemCount () > 0). If your data is loaded asynchronously, RecyclerView will wait until the data is loaded before the state can be restored. If you have a default item (such as a Header or load indicator) as part of your adapter, you should use the PREVENT option unless the default item is added using MergeAdapter. MergeAdapter waits for all adapters to be ready before resuming state

PREVENT

State will not be restored until ALLOW or PREVENT_WHEN_EMPTY is configured

The usage is as follows:

adapter.stateRestorationPolicy = PREVENT_WHEN_EMPTY
Copy the code

Add the above configuration even asynchronous loading data can restore the RecyclerView position

Set the PREVENT_WHEN_EMPTY

Trace introduction process

As usual, let’s follow the official Commit log to see how this works

First let’s look at the Feature mentioned in IssueTracker

IssueTracker

When asynchronous data is loaded, the RecyclerView state cannot be restored. Adapter should provide relevant solutions

Interestingly, this feature reimplements the previous version’s logic, which I see in the Git Commit log

Revert operation

To prevent LayoutManager#onRestore from executing more than once, the original implementation is not used. Yigit Boyar (the developer of the submission) still wanted to use the original implementation, but the LayoutManager#onRestoreInstance status was public, so there was a compromise

New implementation scheme
No option

In the past, developers would inadvertently call the onRestoreInstanceState(State) method. For example, some developers have used it to manually set their updated state so that even if the state has been restored before, passing the state here will cause LayoutManager to receive it and update its internal state accordingly. Therefore, even though it may seem strange, requestLayout must always be called to preserve functionality

Source code analysis

Next we will analyze this part of the source code, the content is very little, so let’s look at it in detail

The first step is to introduce an enumeration of StateRestorationPolicy


Then you need to provide setStateRestorationPolicy and getStateRestorationPolicy method, we also need a way to judge whether to pass SavedState LayoutManager


The previous setStateRestorationPolicy method called notifyStateRestorationPolicyChanged, NotifyStateRestorationPolicyChanged for static class AdapterDataObservable method, in the other methods in this class we are familiar with, all is to refresh the data in the Adapter.

notifyStateRestorationPolicyChanged

And call in notifyStateRestorationPolicyChanged mObservers onStateRestorationPolicyChanged method of elements in the list, Through the source code we learn that the types of elements in the list as AdapterDataObserver, so need to join in the AdapterDataObserver onStateRestorationPolicyChanged method

onStateRestorationPolicyChanged

This method is an empty implementation and RecyclerViewDataObserver overrides it

RecyclerViewDataObserver

Now that you have configured the recovery policy and listened when the recovery policy changes, the next thing to do is to restore the previous state if the installation was to be restored

Restore the state

Note: The StateRestorationPolicy was called the StateRestorationStrategy before it was released, and has since been named StateRestorationPolicy. Alpha libraries may change API names and delete apis at any time. So if you’re looking at the source code for this section, please take note

At this point, the relevant source code is here

conclusion

StateRestorationPolicy provides RecyclerView asynchronous loading data recovery rolling position solution. The idea is to configure StateRestorationPolicy to change the recovery policy and call the requestLayout method when the policy changes. Restore state in the dispatchLayoutStep2() method (which is called in the onLayout and measure methods) (if canRestoreState() returns true)

The demo address

A little thought: We all know that ViewPager2 is implemented using RecyclerView, so what can we do with this API?

Leave your thoughts in the comments section

About me

I am a Fly_with24

  • The Denver nuggets

  • Jane’s book

  • Github