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
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
For more information about state saving, see AndroidX SaveState ViewModel-SavEstate analysis
This is also true
serendipity
Recently I saw Florina Muntenescu’s Restore RecyclerView Scroll Position, which introduced “RecyclerView.Adapter lazy State Restoration”. That piqued my interest
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
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“
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
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
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
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.
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
This method is an empty implementation and RecyclerViewDataObserver overrides it
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
❝
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