关键词:
android 浅析RecyclerView回收复用机制及实战,仿探探效果
还是老套路,先来看看实现的效果!
浅析RecyclerView回收复用机制
在写这个效果之前,需要熟悉Rv的回收复用机制,因为实现这个效果,需要自定义LayoutManager()
…
众所周知,RecyclerView 是一个可滑动的View,那么他的回收/复用入口一定是在onTouchEvent()
事件中
滑动过程中响应的是MotionEvent.ACTION_MOVE
事件,所以直接来这里找找看!!
缓存机制-onTouchEvent()入口
#RecyclerView.java
@Override
public boolean onTouchEvent(MotionEvent e)
final int action = e.getActionMasked();
switch (action)
........................................
........只展示代码思路,细节请自行查看........
........................................
case MotionEvent.ACTION_MOVE:
if (mScrollState == SCROLL_STATE_DRAGGING)
mLastTouchX = x - mScrollOffset[0];
mLastTouchY = y - mScrollOffset[1];
// 关键代码1
if (scrollByInternal(
canScrollHorizontally ? dx : 0,
canScrollVertically ? dy : 0,
vtev))
getParent().requestDisallowInterceptTouchEvent(true);
if (mGapWorker != null && (dx != 0 || dy != 0))
mGapWorker.postFromTraversal(this, dx, dy);
break;
接着找scrollByInternal(int x, int y, MotionEvent ev)
方法
#RecyclerView.java
boolean scrollByInternal(int x, int y, MotionEvent ev)
if (mAdapter != null)
........................................
........只展示代码思路,细节请自行查看........
........................................
if (x != 0)
// 关键代码2 去到 LinearLayoutManager 执行fill方法
consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState);
unconsumedX = x - consumedX;
if (y != 0)
// 关键代码2 去到LinearLayoutManager 执行fill方法
consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState);
unconsumedY = y - consumedY;
....
现在走到了mLayout.scrollHorizontallyBy(x, mRecycler, mState);
接着去LinearLayoutManager()
中去找scrollHorizontallyBy()
方法
#LinearLayoutManager.java
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
RecyclerView.State state)
if (mOrientation == HORIZONTAL)
return 0;
// 关键代码3
return scrollBy(dy, recycler, state);
scrollBy()
->
#LinearLayoutManager.java
int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state)
........................................
........只展示代码思路,细节请自行查看........
........................................
final int consumed = mLayoutState.mScrollingOffset
// 关键代码4
+ fill(recycler, mLayoutState, state, false);
接着找到fill()
方法
#LinearLayoutManager.java
int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
RecyclerView.State state, boolean stopOnFocusable)
if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN)
// 关键代码19 缓存ViewHolder
recycleByLayoutState(recycler, layoutState);
// 循环调用
while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state))
// 关键代码5 [用来4级复用]
layoutChunk(recycler, state, layoutState, layoutChunkResult);
........................................
........只展示代码思路,细节请自行查看........
........................................
看到这里只需要记住以下两点即可:
- recycleByLayoutState(recycler, layoutState); 缓存ViewHolder
- layoutChunk(recycler, state, layoutState, layoutChunkResult); 四级复用
有人可能会问,这里为什么是四级?不是说的三级嘛?
其实三级和四级都无所谓,知识点是不会变的,只是层级越多,理解就越深刻,越细罢了
直接进入到缓存的代码:
#LinearLayoutManager.java
private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState)
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START)
// 关键代码21 缓存底部
recycleViewsFromEnd(recycler, layoutState.mScrollingOffset);
else
// 关键代码20 缓存头部
recycleViewsFromStart(recycler, layoutState.mScrollingOffset);
这里如果是向下滑动,就会缓存头部那么就会执行到recycleViewsFromStart()
如果是向上滑动,就会缓存尾部那么就会执行到recycleViewsFromEnd()
recycleViewsFromStart()
和 recycleViewsFromEnd()
随便点开一个看看,里面代码都差不多一样.
#LinearLayoutManager.java
private void recycleViewsFromStart(RecyclerView.Recycler recycler, int dt)
if (mShouldReverseLayout)
for (int i = childCount - 1; i >= 0; i--)
...
// 关键代码22
recycleChildren(recycler, childCount - 1, i);
return;
else
for (int i = 0; i < childCount; i++)
...
// 关键代码23
recycleChildren(recycler, 0, i);
return;
这里无论走哪一个if()
都会走到recycleChildren()
方法
#LinearLayoutManager.java
private void recycleChildren(RecyclerView.Recycler recycler, int startIndex, int endIndex)
if (startIndex == endIndex)
return;
if (endIndex > startIndex)
for (int i = endIndex - 1; i >= startIndex; i--)
// 移除View 关键代码23 [执行到RecyclerView.removeAndRecycleViewAt()]
removeAndRecycleViewAt(i, recycler);
else
for (int i = startIndex; i > endIndex; i--)
removeAndRecycleViewAt(i, recycler);
接着这里会执行到RecyclerView
的removeAndRecycleViewAt()
方法
#RecyclerView.java
// 关键代码24
public void removeAndRecycleViewAt(int index, Recycler recycler)
final View view = getChildAt(index);
removeViewAt(index);
// 关键代码25
recycler.recycleView(view);
继续往下执行
#RecyclerView.java
public void recycleView(View view)
.......
ViewHolder holder = getChildViewHolderInt(view);
// 缓存
recycleViewHolderInternal(holder);
接着继续执行recycleViewHolderInternal()
#RecyclerView.java
void recycleViewHolderInternal(ViewHolder holder)
........................................
........只展示代码思路,细节请自行查看........
........................................
boolean cached = false;
if (forceRecycle || holder.isRecyclable())
// mViewCacheMax = 缓存的最大值
// mViewCacheMax = 2
// 如果viewHolder是无效、未被移除、未被标记的
if (mViewCacheMax > 0
&& !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
| ViewHolder.FLAG_REMOVED
| ViewHolder.FLAG_UPDATE
| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN))
int cachedViewSize = mCachedViews.size();
// 关键代码24
// mViewCacheMax = 2
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0)
// 如果viewholder存满2个则移除第0个位置
// 保证mCachedViews 最多能缓存2个ViewHolder
recycleCachedViewAt(0);
cachedViewSize--;
....
// 保存ViewHolder数据 [mCachedViews数据不会超过2个]
mCachedViews.add(targetCacheIndex, holder);
cached = true;
if (!cached)
// 当ViewHolder不改变时候(只有一个ViewHolder) 就会直接存到缓存池中
addViewHolderToRecycledViewPool(holder, true);
recycled = true;
........................................
........只展示代码思路,细节请自行查看........
........................................
通过 关键代码24 可知,mCachedViews 最多能保存2个ViewHolder
如果第三个ViewHolder来临的时候,就会先删除掉第0个,然后在 mCachedViews.add(targetCacheIndex, holder);
然后再来看看 recycleCachedViewAt(0)
的细节!
#RecyclerView.java
void recycleCachedViewAt(int cachedViewIndex)
...
ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);
// 关键代码25
// 添加到ViewPool到缓存里面取
addViewHolderToRecycledViewPool(viewHolder, true);
// 将第0个ViewHolder移除
mCachedViews.remove(cachedViewIndex);
继续执行到 addViewHolderToRecycledViewPool()
方法
将mCachedViews.get(0)
中的ViewHolder
获取出来,添加到缓存池中,并删除
#RecyclerView.java
void addViewHolderToRecycledViewPool(ViewHolder holder, boolean dispatchRecycled)
.....
// 向缓存池中 保存ViewHolder 关键代码28
getRecycledViewPool().putRecycledView(holder);
点进来看看putRecycledView()
方法
#RecyclerView.java
// SparseArray 类似与 HashMap<int,ScrapData>
// 特点: key相同会保留最后一个,
// 会根据key的int值排序(从小到大)
SparseArray<ScrapData> mScrap = new SparseArray<>();
public void putRecycledView(ViewHolder scrap)
// 获取ViewHolder布局类型
final int viewType = scrap.getItemViewType();
// 根据布局类型来获取ViewHolder
final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap;
// 判断缓存池的大小
// mScrap.get(viewType).mMaxScrap 默认为 5
// 同一种ViewType 只保存5个ViewHolder
if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size())
return;
// 清空ViewHolder记录
scrap.resetInternal();
//add
scrapHeap.add(scrap);
// 清空ViewHolder记录
void resetInternal()
mFlags = 0recyclerview缓存复用解析,源码解读(代码片段)
...如何工作的2.源码时序图和解读2.1缓存回收LinearLayoutManagerRecyclerView2.2缓存复用LinearLayoutManagerRecyclerView关于mChangedScrap2.3回收池结构时序图代码参考材料RecyclerView有四级缓存,其中一级缓存是用户自定义的缓存,四级缓存本... 查看详情
recyclerview缓存复用解析,源码解读(代码片段)
...如何工作的2.源码时序图和解读2.1缓存回收LinearLayoutManagerRecyclerView2.2缓存复用LinearLayoutManagerRecyclerView关于mChangedScrap2.3回收池结构附:时序图代码参考材料RecyclerView有四级缓存,其中一级缓存是用户自定义的缓存,四... 查看详情
recyclerview的缓存机制(代码片段)
原文链接原文出处:基于滑动场景解析RecyclerView的回收复用机制原理前言之前优化Feed流框架的时候,看到过一篇基于滑动场景分析RecyclerView回收复用的文章,感觉十分经典,因此转载复习之。正题RecyclerView的回收... 查看详情
recyclerview使用大全
...recylerview即回收view也可以看出。官方对于它的介绍则是:RecyclerView是ListView的升级版本,更加先进和灵活。RecyclerView通过设置LayoutManager,ItemDeco 查看详情
listview与recyclerview对比浅析——缓存机制
https://www.jianshu.com/p/193fb966e954 一,背景RecyclerView是谷歌官方出的一个用于大量数据展示的新控件,可以用来代替传统的ListView,更加强大和灵活。最近,自己负责的业务,也遇到这样的一个问题,关于是否要将ListView替换为Rec... 查看详情
recyclerview的复用缓存机制
...分析缓存复用机制时,先去缓存与复用的时机在哪里。在RecyclerView滑动时,item会显示出来。所以首先先想到在onTouchEvent()中ACTION_MOVE事件里做了什么事。接着又到scrollStep(x,y,mReusableIntPair)->mLayout.scrollVerticallyBy(dy,mRecycler,mState)->... 查看详情
这recyclerview的特效,谁看了不说6(代码片段)
...制,因为实现这个效果,需要自定义LayoutManager()…众所周知,RecyclerView是一个可滑动的View,那么他的回收/复用入口一定是在onTouchEvent()事件中滑动过程中响应的是MotionEvent.ACTION_MOVE事件,所以直接来这里找找看!!缓存机制onTouchEvent()入口... 查看详情
时光轴二之recyclerview版时光轴效果
因为现在RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,但是直接把viewholder的实现封装起来,用户只要实现自己的viewholder就可以了,该组件会自动帮你回收复用每... 查看详情
时光轴二之recyclerview版时光轴效果
由于如今RecyclerView是support-v7包中的新组件,是一个强大的滑动组件。与经典的ListView相比,相同拥有item回收复用的功能,可是直接把viewholder的实现封装起来,用户仅仅要实现自己的viewholder就能够了,该组件会自己主动帮你回收... 查看详情
recyclerview使用大全
转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/54098101RecylerView介绍RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字recylerview即回收view也... 查看详情
android踩坑日记:recyclerview中edittext和imageview的viewholder复用坑
RecyclerView中EditText和ImageView的ViewHolder复用坑RecyclerView作为ListView的升级版,目前来讲讲开发过程遇到的坑。RecyclerView中使用EditText滚动后数据消失,错乱场景:RecyclerView中的每个Item的ViewHolder布局中为都有EditText控件... 查看详情
recyclerview的使用
什么是RecyclerViewRecyclerView是Android5.0materialsdesign中的组件之一,相应的还有CardView、Palette等。看名字我们就能看出一点端倪,没错,它主要的特点就是复用。我们知道,Listview中的Adapter中可以实现ViewHolder的复用。RecyclerView提供了... 查看详情
android自定义recyclerview分割线,打造无边缘分割线
前言: 现在的RecyclerView几乎已经完全取代ListView和GridView了,已经几年没使用ListView和GridView了,想当年还需要自己在getView方法中复用convertView。而现在的RecyclerView一出生就被设计成convertView复用的,尽管你不想复... 查看详情
android5.x新特性详解——列表与卡片
RecyclerView在Android5.X中将使用了很久的ListView做了升级,增加了一个使用更方便、效率更高的控件——RecyclerView。RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,它同样拥有item回收... 查看详情
Android 电视不显示 Recyclerview
】Android电视不显示Recyclerview【英文标题】:AndroidTvnotdisplayingRecyclerview【发布时间】:2020-05-2819:46:29【问题描述】:我在我的androidtv应用程序中创建了一个回收站视图,但它没有显示任何内容,我这样做就像我为移动应用程序所... 查看详情
用十张图帮你解析recyclerview的缓存复用机制了~(代码片段)
ViewPager2是在RecyclerView的基础上构建而成的,意味着其可以复用RecyclerView对象的绝大部分特性,比如缓存复用机制等。本篇的主要目的是快速普及必要的前置知识,而内容的核心,正是前面所提到的RecyclerView的缓存... 查看详情
recyclerview使用大全
...erview即回收view也可以看出。官方对于它的介绍则是:RecyclerView是ListView的升级版本,更加先进和灵活。RecyclerView通过设置LayoutManager,ItemDecoration,ItemAnimator实现你想要的效果。使用LayoutManager来确定每一个item的排... 查看详情
Android RecyclerView 项目动态布局
】AndroidRecyclerView项目动态布局【英文标题】:AndroidRecyclerViewitemdynamiclayout【发布时间】:2020-08-1311:21:02【问题描述】:在我的回收器视图项目布局中,我想添加类似水平回收器视图布局的东西,因为我不知道我需要多少个ImageVie... 查看详情