为了更清晰的观察
recycleView
缓存复用,在看到有一篇文章是打印缓存相关信息后,觉着确实是一种办法,比打断点更合适查看缓存的变化情况,就尝试自己写了写。
这里我主要利用反射观察的是:mCachedViews
和 recycleViewPool
里面的变化情况。代码如下:
1 | public void getInfo(){ |
需要注意的是:反射获取
然后在 recycleView
滚动的时候,显示信息:
1 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { |
还有可以在 adapter
重写方法: onViewRecycled(ViewHOlder holder)
方法,可以查看最新被回收的位置ViewHolder
:
1 |
|
这样我们就可以通过日志的方式来近距离查看
recyclerView
复用回收。
我们假设这样一个场景:总共假设有20个item
,使用 GrideLayoutManager
每行显示5个,一个屏幕差不多显示两行,如下图所示:
我们在 adapter
的 onCreateViewHolder
和 onBindViewHolder
方法的地方都打印日志,并且重写 onViewRecycled
方法,查看 View
的回收情况。
当我们向下滑动,将第一行的数据滑出屏幕后,我们发现打印日志如下:
我们发现 2,3,4卡位的 ViewHolder
被回收了。这里的被回收是指添加到 RecycleViewPool
当中了。
此时 mCachedViews
中的缓存信息如下:
从日志上来看,它缓存了:1,0,15,16,17,18,19共7个卡位的数据。
这里补充一下:
mCachedViews
的大小在源码定义中默认是:static final int DEFAULT_CACHE_SIZE = 2;
(当然也可以自己设置,通过RecyclerView #setItemViewCacheSize
,一般不设置)经过我的多次实验观察,当每行设置为5列时,mCachedViews.size == 2+ 5 = 7
,当每行是4时,mCachedViews.size == 2+ 4 = 6
,所以此时就是mCachedView.size 是7
。
问题1:为什么mCachedViews
缓存的卡位是1,0,15,16,17,18,19?
要回答这个问题,首先应该明白当我们在滑动第三行展示的时候,此时 RecyclerView
创建了第四行的 ViewHolder
,即 15,16,17,18,19因为它们未曾展示到屏幕上,所以被 mCachedViews
缓存,继续滑动,第一行数据移出屏幕之外,也要回收了,0,1,2,3,4,5 这5个是将要被缓存,但是mCachedVIews
已经缓存了5个,势必只能再添加两个,两外三个卡位的 ViewHolder
将要被回收,GrideLayoutManager
默认从右往左回收:
第一次回收4,3卡位如图:
第二次回收2卡位如图:
因为此时缓存数量已到最大值7了,所以再次添加时,会移除第一个。代码如下:
1 | int cachedViewSize = mCachedViews.size(); |
日志:
新缓存的2卡位被插入index = 1
的位置。
如此,我们就可以知道当1卡位会回收时,mCachedViews
中缓存的信息应该是,先移除第0个,也就是position= 3
的 ViewHolder
,插入到 index = 1
的位置,顺序应该是:2,1,15,16,17,18,19,好我们看下日志:
是的,不出我们所料,至此到最后我们就知道了,当0卡位被回收时,mCachedViews
的缓存信息就是:1,0,15,16,17,18,19. 被移除的ViewHolder
被添加到了 RecycleViewPool
当中了,从 RecycleViewPool
当中取出的 ViewHolder
类似于全新的,但是不会重新调用 onCreateViewHolder
,会重新调用 onBindViewHolder
重新绑定数据。