Android RecyclerView 回收/复用 笔记

RecyclerView,看名字就知道,这玩意儿的精髓在于回收/复用。

  1. 复用了啥?
    View
  2. 哪里会触发回收/复用?
    • MOVE事件
      a. onTouchEvent
      b. MotionEvent.ACTION_MOVE
      c. scrollByInternal
      d. scrollStep
      e. LayoutManager的scrollHorizontallyBy/scrollVerticallyBy
      - 这里看LinearLayoutManager中具体实现
      a. scrollBy
      b. fill
      c. layoutChunk这个方法是在一个while循环里调用的
      d. View view = layoutState.next(recycler); 获取View
      e. addView(view); 使用View
      f. layoutState.next这里重点跟这个方法
      g. recycler.getViewForPosition
      这里已经找到了回收/复用关键Recycler类
      a. recycler.getViewForPosition
      b. tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView
      c. 上面是那个ViewHolder之后直接拿itemView,这样问题就转变成了怎么拿ViewHolder
      d. tryGetViewHolderForPositionByDeadline
    • notify数据变化
  3. 怎么回收/复用?
    Recycler类:
    下面几个数据结构用来缓存回收的ViewHolder。
        final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
        ArrayList<ViewHolder> mChangedScrap = null;
    
        final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
        
        RecycledViewPool mRecyclerPool;
    
        private ViewCacheExtension mViewCacheExtension;
    
    a. mAttachedScrap 和 mChangedScrap 用来缓存屏幕内的 ViewHolder
    - 其中mChangedScrap主要服务于动画
    b. mCachedViews 用来缓存屏幕外的 ViewHolder
    - 默认缓存2个
    - 通过setViewCacheSize可改变缓存容量
    c. mViewCacheExtension 用户自定义缓存机制
    d. mRecyclerPool 用来缓存屏幕外的 ViewHolder
    - 从mCachedViews中淘汰的ViewHolder会被缓存到 mRecyclerPool 中
    - mRecyclerPool 是根据 type 来获取 ViewHolder,每个 type 默认最大缓存 5 个。可通过setMaxRecycledViews(int viewType, int max) 设置自定义大小。
    - RecycledViewPool lets you share Views between multiple RecyclerViews.
    - 也就是说,当多个RecyclerView使用相同的ViewHolder时,可以共享缓存。
    - ViewHolder 在被缓存到 RecycledViewPool 时,会将内部的数据清理,因此从 RecycledViewPool 中取出来的 ViewHolder 需要重新调用 onBindViewHolder 绑定数据
#回收:
RecyclerView - onLayout
RecyclerView - dispatchLayout
RecyclerView - dispatchLayoutStep2();
mLayout.onLayoutChildren(mRecycler, mState);
LinearLayoutManager - onLayoutChildren
LinearLayoutManager - detachAndScrapAttachedViews
LinearLayoutManager - scrapOrRecycleView
        ``` 
        if (viewHolder.isInvalid() && !viewHolder.isRemoved()
                && !mRecyclerView.mAdapter.hasStableIds()) {
            removeViewAt(index);
            recycler.recycleViewHolderInternal(viewHolder);
        } else {
            detachViewAt(index);
            recycler.scrapView(view);
            mRecyclerView.mViewInfoStore.onViewDetached(viewHolder);
        }
        ```
    - recycler.recycleViewHolderInternal(viewHolder)
    - recycler.scrapView(view);
兜兜转转,最后终于找到Recycler了
###recycleViewHolderInternal
    处理屏幕外缓存
###scrapView
    处理屏幕内缓存


#复用:
流程都在 tryGetViewHolderForPositionByDeadline 中
###大体流程:
a. 从屏幕内缓存找
b. 从mCachedViews缓存找
c. 从mViewCacheExtension缓存找
d. 从mRecyclerPool找
e. 找不到,调用adapter的create方法

###代码流程:
a. getChangedScrapViewForPosition
    - If there is a changed scrap, try to find from there
    - 从 mChangedScrap 找
b. getScrapOrHiddenOrCachedHolderForPosition
    - Find by position from scrap/hidden list/cache
    - 从 mAttachedScrap和mCachedViews找
    - 这里是根据Position
c. getScrapOrCachedViewForId
    -  Find from scrap/cache via stable ids, if exists
    - 依然通过 mAttachedScrap和mCachedViews找
    - 这里是根据ID
d. mViewCacheExtension.getViewForPositionAndType(this, position, type);
    - We are NOT sending the offsetPosition because LayoutManager does not know it.
    - 从mViewCacheExtension中找
e. holder = getRecycledViewPool().getRecycledView(type);
    - 从mRecyclerPool中找
f. holder = mAdapter.createViewHolder(RecyclerView.this, type);
    - 直接通过Adapter的createViewHolder的创建
g. tryBindViewHolderByDeadline
    - 绑定数据
    - mAdapter.bindViewHolder(holder, offsetPosition);
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容