This article has authorized the WeChat public address. guolin_blog ( Guo Lin) Exclusive release

Recently under study RecyclerView Recycling and reuse mechanism of, By the way. We know,RecyclerView stay layout son View
Time, All are managed through recycling mechanism. There are a lot of articles about the analysis and explanation of recycling mechanism on the Internet, The analysis is very detailed, What level 4 cache, First go mChangedScrap
Where to pick it up or something like that; But actually, What I want to say is,RecyclerView
The recycling mechanism of is really perfect, Covering various scenes, But not every scenario will go through all the processes of the mechanism when it is recycled. For example, stay
setLayoutManager,setAdapter,notifyDataSetChanged
Or when sliding and so on, these scenarios will trigger the work of recycling mechanism. But if it's just RecyclerView When the recycling mechanism triggered by the sliding scene works, In fact, it doesn't need to involve all four levels of cache.


emmm, I'm still a little confused, Then keep reading, I will analyze it slowly and little by little. This article will not be like other great gods' articles, Analyze the recycling mechanism source line by line, I don't have the ability, So I will analyze the source code based on a specific scenario, It will be easier to understand. End of garbage, Get down to business.

Topic

RecyclerView The internal implementation of the recycling and reuse mechanism of Recycler Inner class implementation, The following are all explained with such a page sliding scene RecyclerView
Recycling and reuse mechanism of.



Corresponding version:
RecyclerView: recyclerview-v7-25.1.0.jar
LayoutManager: GridLayoutManager extends LinearLayoutManager
(recyclerview-v7-25.1.0.jar)

Each line of this page can be displayed5 A card position, For each card position item layout type Agreement.

Before analyzing the recycling mechanism, A few questions first:

Q1: If sliding down, New line5 The display of card bits will be de multiplexed
ViewHolder, First line5 Card positions will be removed from the screen and recycled, So in the process, Reuse before recycling? Recycle before reuse? Or recycle and reuse? In other words, New line5 Multiple card positions
ViewHolder Maybe the first line was recycled5 A card??

Before the second question, Look at some pictures first:



Black box indicates screen,RecyclerView Slide down first, The third line shows the card position, Slide up again, The third line moves out of the screen, The first line is displayed. We are at Adapter Of
onCreateViewHolder() and onBindViewHolder() Log in, Here is the log of this process:



Red box1 yes RecyclerView Log of slide down operation, Third elements5 The display of each card position is recreated ViewHolder
; Red box2 Is the log when you slide up again, first line5 For redisplay of card positions ViewHolder It's all reusable, Because no create viewHolder
Log, And then just the back3 Card bits rebind data, CalledonBindViewHolder(); So here comes the question...:

Q2: In the process, Why do RecyclerView Slide up again to redisplay the5 When a card is in place, Only behind3 Card position triggered
onBindViewHolder() Method, Rebind the data? Mingming5 Each card is reused.

Based on the above operation, Let's move on:



Based on the operation of the second question, It has been created15 individual ViewHolder, The display is No1,2 Line card position, Then continue to slide down twice, The log of this process is as follows:


Red box1 Is the log of the second problem operation, It's just to show that the next log will continue to operate on the basis of the above;

Red box2 Is the log of the first downward slide, Contrast problem2 Log, This third line5 For each card position ViewHolder They're all reused, And there's only the back3 Card position triggered
onBindViewHolder() Rebind data;

Red box3 Is the log for the second slide down, This time in line four5 A card position, Front3 For card positions of ViewHolder It is multiplexed. behind2 Card position ViewHolder
Is recreated, And5 All the cards are called onBindViewHolder() Rebind data;

that,

Q3: And then slide up and down, Slipping several times, No more onCreateViewHolder() Log. In other words RecyclerView
A total of17 individual ViewHolder, But sometimes in a row5 There are only3 Card bits need to be rebound, But sometimes5 Data rebinding is required for all card positions, Why is that?

If you understand RecyclerView Recycling and reuse mechanism of, Then all three problems will be solved; Conversely, If you know the cause of these three problems, Understanding then RecyclerView
The recycling and reuse mechanism is simpler; therefore, With problems, When analyzing the source code in a specific scenario, It should be easier.

Source code analysis

actually, According to the problem2 Log, We can answer the questions1 了. Display at present1,2 That's ok,
ViewHolder The number of10 On the basis of, Third elements5 New card positions need to be recreated before they can be displayed
ViewHolder, In other words, In this downward sliding process, yes5 The reuse mechanism of new card bits works first, Then the first1 Row5 Card positions removed from the screen are recycled.

that, Let's first look at the source code of the reuse mechanism

Multiplexing mechanism

getViewForPosition()







This method is the entrance of reuse mechanism, that is Recycler Open to external usersapi, You can call this method externally to return what you want View, And as for this View
It's reuse, Or recreated, All by Recycler Internal implementation, External concealment.

tryGetViewHolderForPositionByDeadline()

therefore,Recycler The internal implementation of the reuse mechanism of is in this method.
Before analyzing logic, Have a look first Recycler Some structures of, Used for caching ViewHolder Of.



mAttachedScrap: Used to cache the item Of ViewHolder, The scene seems to be RecyclerView stay onLayout
I will put them first. children All removed. Add it again, So this List It should be used for temporary storage during layout children Of, Anyhow RecyclerView
You won't find reuse in this during sliding ViewHolder That's it..

mChangedScrap: I don't understand why this is used, Look at the name ViewHolder When the data of, stay RecyclerView
In the process of sliding, I didn't find any reuse here ViewHolder, So this one can be put aside for a while.

mCachedViews: This is much more important, Recycling and reuse in the sliding process are all handled first List, It's in this collection ViewHolder
The original data and information of, So it can be added directly to RecyclerView Display in, No need to re onBindViewHolder().

mUnmodifiableAttachedScrap: I don't know why, Temporary skip.

mRecyclerPool: This is also important, But it's here ViewHolder Will be reset, Amount to ViewHolder
It's a new one, So we need to call it again onBindViewHolder To bind data.

mViewCacheExtension: This is for our own expansion, It doesn't seem to work, I will not analyze it for the time being.

So let's look at the logic of reuse:



The first step is simple,position If in item Beyond the scope of, Let's throw the exception away. Keep looking down



If yes isPreLayout() Time, Then go. mChangedScrap Find in.
Then this isPreLayout What is it? There are two assignments.





emmm, It seems, stay LayoutManager Of onLayoutChildren It will be set as
false, But I still don't understand what this process is about, It seems that
mState.mInPreLayou = false, So it's not coming here, Skip for now. Continue downward.



Follow up on this method



First, go mAttachedScrap Search for position Coincident viewHolder, Some conditions need to be matched, About this viewHolder
Not removed, It's a valid condition or something, If you're satisfied, go back to this viewHolder.

therefore, The key here is to understand this mAttachedScrap In the end what is it? What is the deposit ViewHolder.

Operation of a remote control key, Whether or not it slips, Will lead to RecyclerView Re onLayout, That should be layout Words,RecyclerView
I'll put all the children before remove fall, And then again add Up, Finish once layout Process. So this is temporary remove Dropped
viewHolder Where to store it, Here it is mAttachedScrap Medium, That's what I understand.

therefore, Feel this mAttachedScrap Stored in viewHolder It has little to do with recycling and reuse.

There are some analysis articles on the Internet,RecyclerView When reusing, it will go in order mChangedScrap, mAttachedScrap
Wait, wait, look in the cache, If you don't find it, go down there, From the code point of view, that's right, But I think there's something wrong with that. Because this article is based on RecyclerView
For the sliding scene of, Reuse of new card and recovery mechanism of old card, It doesn't even involvemChangedScrap and
mAttachedScrap, So I think it's better to analyze the corresponding recycling mechanism based on a certain scenario. Just likemChangedScrap
I don't understand what it's for, But I guess it should be a reuse scenario that will only be involved when the data changes, So when I analyze reuse based on sliding scenes, Even if I don't understand this, It's not going to have a big impact.

Keep looking down



emmm, I still don't understand this passage, But it is estimated that some reuse strategies used in specific scenarios should be needed, Look at the name, Should follow hidden
Of? Don't you understand? Skip this paragraph. It should be ok, Recycling in the sliding process should have little to do with this.



Here's the point, Take notes take notes, Reuse in a sliding scenario uses the mechanism here.

mCachedViews The default size of is2. ergodic mCachedViews, find position Coincident
ViewHolder, I said before,mCachedViews Stored in ViewHolder Data and information of, therefore mCachedViews
It can be understood as, Only the original card can reuse this ViewHolder, The new position of the card cannot be changed from mCachedViews Li Na ViewHolder Come out with.

find viewholder after



even if position Match found ViewHolder, You need to judge this ViewHolder Has it been remove fall,type
Inconsistent types, as follows.



The above is in mCachedViews Search for, If we don't find it, Just keep looking, Just passed position
Come looking for, Then this timeid, Then repeat the above steps and find again, as follows



getScrapOrCachedViewForId() Do things with getScrapOrHiddenOrCacheHolderForPosition()
In fact, it's almost the same, Only one is through position Come looking for ViewHolder, One is through id Come looking for. And this id It's not that we're here xml Set in
android:id, But Adapter A property held by, This property will not be used by default, So this5 It's not going to happen, Unless we rewrite it Adapter Of
setHasStableIds(), Since it's not a common scene, Let's skip it, So keep going.



This is often called extension class,RecyclerView Extension classes provided for our custom implementation, We can rewrite getViewForPositionAndType()
Method to implement its own reuse strategy. However, No use. Then this part will not be implemented, Skip over. Continue downward



Here's the point, Take notes take notes.

Here we go. RecyclerViewPool Li takes ViewHolder,ViewPool According to different item type Create different List, each
List The default size is5 individual. Look at it. ViewPool How to find it



I said before,ViewPool According to different viewType Create different collections to store ViewHolder, When reusing, as long as ViewPool Same in
type Yes ViewHolder Cache words, Just take the last one out and reuse it, No need mCachedViews Various matching conditions are required, It can be reused as long as it has.

Keep looking." Chart No.7 step" Later code, Get ViewHolder after, It will be called again resetInternal() Reset ViewHolder, such
ViewHolder Can be treated as a brand new ViewHolder Came to use. That's why it's taken from here ViewHolder All need to be renewed
onBindViewHolder() 了.

If so ViewPool I still haven't found it, Keep looking down



If ViewPool None of them ViewHolder To use, Then call it. Adapter Of onCreateViewHolder To create a new
ViewHolder Use.

There are many steps above ViewHolder, No matter what step, Just find ViewHolder
Words, Then we don't need to worry about the next steps, Then we need to continue to judge whether we need to rebind the data, Also check whether the layout parameters are legal. as follows:



Come here,tryGetViewHolderForPositionByDeadline() That's the end of it. This is about RecyclerView
Reuse mechanism of, In the middle, we jumped a lot, because RecyclerView There are various scenes to refresh him view, For example, re setLayoutManager(), again
setAdapter(), perhaps notifyDataSetChanged(), Or slide and so on, Just relayout, It's going to be recycled and reused
ViewHolder, So this reuse mechanism needs to consider various scenarios.

It's a bit hard to chew through the lines of code, So I just use RecyclerView To analyze the recycling and reuse mechanism involved.

Let's analyze the recycling mechanism

Recovery mechanism

There are many entrances to the recycling mechanism, because Recycler There are various structures, such asmAttachedScrap,mCachedViews
Wait, The recovery time of different structures is different, There are more entrances.

therefore, Or based on RecyclerView Under the sliding scene of, When the card position of the screen is removed for recycling, the entrance is:



The slide scene of this analysis, stay RecyclerView Sliding time, Will be handed over to LinearLayoutManager Of scrollVerticallyBy()
To process, Then? LayoutManager Will then call fill() Method to deal with the card bits that need to be reused and recycled, Final meeting调用上述 recyclerView()
这个方法开始进行回收工作.











回收的逻辑比较简单,由 LayoutManager 来遍历移出屏幕的卡位,然后对每个卡位进行回收操作,回收时,都是把 ViewHolder 放在
mCachedViews 里面,如果 mCachedViews 满了,那就在 mCachedViews 里拿一个 ViewHolder 扔到 ViewPool
缓存里,然后 mCachedViews 就可以空出位置来放新回收的 ViewHolder 了.

总结一下:

RecyclerView 滑动场景下的回收复用涉及到的结构体两个:
mCachedViews 和 RecyclerViewPool

mCachedViews 优先级高于 RecyclerViewPool,回收时,最新的 ViewHolder 都是往 mCachedViews
里放,如果它满了,那就移出一个扔到 ViewPool 里好空出位置来缓存最新的 ViewHolder.

复用时,也是先到 mCachedViews 里找 ViewHolder,但需要各种匹配条件,概括一下就是只有原来位置的卡位可以复用存在
mCachedViews 里的 ViewHolder,如果 mCachedViews 里没有,那么才去 ViewPool 里找.

在 ViewPool 里的 ViewHolder 都是跟全新的 ViewHolder 一样,只要 type
一样,有找到,就可以拿出来复用,重新绑定下数据即可.

整体的流程图如下:(可放大查看)



最后,解释一下开头的问题

Q1:如果向下滑动,新一行的5个卡位的显示会去复用缓存的
ViewHolder,第一行的5个卡位会移出屏幕被回收,那么在这个过程中,是先进行复用再回收?还是先回收再复用?还是边回收边复用?也就是说,新一行的5个卡位复用的
ViewHolder 有可能是第一行被回收的5个卡位吗?

答:先复用再回收,新一行的5个卡位先去目前的 mCachedViews 和 ViewPool
的缓存中寻找复用,没有就重新创建,然后移出屏幕的那行的5个卡位再回收缓存到 mCachedViews 和 ViewPool
里面,所以新一行5个卡位和复用不可能会用到刚移出屏幕的5个卡位.

Q2: 在这个过程中,为什么当 RecyclerView 再次向上滑动重新显示第一行的5个卡位时,只有后面3个卡位触发了
onBindViewHolder() 方法,重新绑定数据呢?明明5个卡位都是复用的.

答:滑动场景下涉及到的回收和复用的结构体是 mCachedViews 和
ViewPool,前者默认大小为2,后者为5.所以,当第三行显示出来后,第一行的5个卡位被回收,回收时先缓存在 mCachedViews,满了再移出旧的到
ViewPool 里,所有5个卡位有2个缓存在 mCachedViews 里,3个缓存在 ViewPool,至于是哪2个缓存在
mCachedViews,这是由 LayoutManager 控制.

上面讲解的例子使用的是 GridLayoutManager,滑动时的回收逻辑则是在父类 LinearLayoutManager
里实现,回收第一行卡位时是从后往前回收,所以最新的两个卡位是0,1,会放在 mCachedViews 里,而2,3,4的卡位则放在 ViewPool 里.

所以,当再次向上滑动时,第一行5个卡位会去两个结构体里找复用,之前说过,mCachedViews 里存放的 ViewHolder
只有原本位置的卡位才能复用,所以0,1两个卡位都可以直接去 mCachedViews 里拿 ViewHolder 复用,而且这里的 ViewHolder
是不用重新绑定数据的,至于2,3,4卡位则去 ViewPool 里找,刚好 ViewPool 里缓存着3个
ViewHolder,所以第一行的5个卡位都是用的复用的,而从 ViewPool 里拿的复用需要重新绑定数据,才会这样只有三个卡位需要重新绑定数据.

Q3:接下去不管是向上滑动还是向下滑动,滑动几次,都不会再有 onCreateViewHolder() 的日志了,也就是说 RecyclerView
总共创建了17个 ViewHolder,但有时一行的5个卡位只有3个卡位需要重新绑定数据,有时却又5个卡位都需要重新绑定数据,这是为什么呢?

答:有时一行只有3个卡位需要重新绑定的原因跟Q2一样,因为 mCachedView 里正好缓存着当前位置的 ViewHolder,本来就是它的
ViewHolder 当然可以直接拿来用.而至于为什么会创建了17个 ViewHolder,那是因为再第四行的卡位要显示出来时,ViewPool
里只有3个缓存,而第四行的卡位又用不了 mCachedViews 里的2个缓存,因为这两个缓存的是6,7卡位的 ViewHolder,所以就需要再重新创建2个
ViewHodler 来给第四行最后的两个卡位使用.


最近刚开通了公众号,想激励自己坚持写作下去,初期主要分享原创的Android或Android-Tv方面的小知识,感兴趣的可以点一波关注,谢谢支持~~