6.RecyclerView缓存机制

RecyclerView的缓存机制包括了那两方面?

RecyclerView缓存和复用的都是ViewHolder,一个ViewHolder相当于是列表中的一个item,因为ViewHolder类中就包含了我们的itemView变量;
然后我们可以从RecylerViewonTouchEvent()滑动事件处理过程ACTION_MOVE中去分析缓存和复用,也可以从RecyclerView中的布局onLayout中去分析缓存和复用.
从缓存中取出ViewHolder复用时不会调用onCreateViewHolderonBinderViewHolder方法,从缓存池中取出ViewHolder复用时会调用onBinderViewHolder方法;如果从缓存和缓存池中都没有取到ViewHolder,则会依次调用onCreateViewHolderonBinderViewHolder方法.

  1. 缓存
  2. 复用

RecyclerView的缓存机制?

  • onLayout()
    • 切入点,在布局的时候去分析缓存机制;或者在fill()方法中的前面部分逻辑recycleByLayoutState()方法中分析,最后会调用recycleViewHolderInternal()方法,先做缓存操作,然后再处理复用
  • dispatchLayout()->dispatchLayoutStep1()和dispatchLayoutStep2()中都会执行onLayoutChildren()
  • (LinearLayoutManager)mLayout.onLayoutChildren(mRecycler, mState)
    • 根据水平布局或者是竖直布局去分析对应LayoutManager,这里我们分析竖直布局
  • detachAndScrapAttachedViews()
    • 在这个方法中会调用fill()方法,这个方法的逻辑与RecyclerView复用机制相同
  • scrapOrRecycleView()
    • recycler.recycleViewHolderInternal(viewHolder)
      • mCachedViews.add(targetCacheIndex, holder)
        • ViewHolder添加到缓存mCacheViews中,如果缓存满了,也就是缓存大小是2,此时需要将缓存mCacheViews中第1个元素添加到缓存池中,然后将缓存中第1个元素删除,最后将新来的ViewHolder添加到缓存中;
        • 从缓存中取的第1个元素在添加到缓存池的过程中,如果缓存池大小也满了,也就是缓存池大小是5,此时就不再对从缓存取出的第1个元素做添加到缓存池的操作;但是在判断缓存池满之前,都会对这些添加到缓存池中的元素做数据清空操作.
      • addViewHolderToRecycledViewPool(holder, true)
        • ViewHolder添加到缓存池,缓存池对象中包含了一个稀疏矩阵(SparseArray)scrap,ScrapData对象中包含了了这种类型对应的集合(ArrayList)mScrapHeap,这个集合就是这种类型的缓存池,注意每种类型的缓存池大小都是5,在ViewHolder添加到缓存池之前,需要清除ViewHolder包含的数据,使得每个缓存池中的数据都是清空过数据的相同ViewHodler,当我们从缓存池中取出数据时,只需要调用数据绑定方法onBindViewHolder()即可,不需要再调用onCreateViewHolder()方法
    • recycler.scrapView(view) 屏幕内的缓存,达到性能优化的目的
      • mChangedScrap.add(holder)
        • 用来刷新单个item而不是全局刷新
      • mAttachedScrap.add(holder)
        • 用来做动画处理

总结:
根据View的绘制流程中的布局onLayout()作为切入点,去分析我们的RecyclerView中的缓存机制;根据条件将ViewHolder添加到mChangedScrap或者mAttachedScrap缓存集合中去;如果没有添加到这两个缓存集合中去,就将ViewHolder添加到mCacheViews缓存集合中去;如果mCacheViews缓存集合已满,则将mCacheViews缓存集合中第一个元素取出添加到缓存池mScrapHeap中去,同时将mCacheViews缓存集合中第一个元素移除.

RecyclerView的复用机制?

  • onTouchEvent()->ACTION_MOVE
    • 切入点:滑动过程中分析复用机制
  • scrollByInternal()->scrollStep()->
  • (GridLayoutManager)mLayout.scrollHorizontallyBy()
    • 这个水平滚动方法的流程和下面竖直方法滚动流程类似,所以就分析竖直滚动方法的流程
  • (LinearLayoutManager)mLayout.scrollVerticallyBy()->scrollBy()
    • 这里分析实现类LinearLayoutManager中的scrollVerticallyBy()方法,因为GridLayoutManager也是继承自LinearLayoutManager
  • fill()
  • layoutChunk()->View view = layoutState.next(recycler);
  • (RecyclerView.Recycler)recycler.getViewForPosition()
  • tryGetViewHolderForPositionByDeadline() 这个方法中就会去从缓存中去取ViewHolder,如果缓存中取到的ViewHolder为null,则会创建ViewHoldler并绑定数据
    • getChangedScrapViewForPosition()
      • mChangedScrap缓存集合中取ViewHolder
    • getScrapOrHiddenOrCachedHolderForPosition()
      • mAttachedScrapmCachedViews缓存集合中通过position取ViewHolder
    • getScrapOrCachedViewForId()
      • mAttachedScrapmCachedViews缓存集合中通过stableIdViewHolder,缓存mCachedViews的最大值是2,int DEFAULT_CACHE_SIZE = 2,我们可以通过这个方法更改缓存大小:setViewCacheSize(int viewCount)
    • mViewCacheExtension.getViewForPositionAndType(this, position, type)
      • 自定义复用,缓存需要自己实现
    • getRecycledViewPool().getRecycledView(type)
      • mScrapHeap缓存集合中取ViewHolder,缓存池的最大值为5, int DEFAULT_MAX_SCRAP = 5,我们可以通过这个方法更改缓存池大小:setMaxRecycledViews(int viewType, int max)
    • mAdapter.createViewHolder
      • 最终调用AdapteronCreateViewHolder()方法创建ViewHolder
    • tryBindViewHolderByDeadline
      • 最终调用AdapteronBinderViewHolder()方法绑定数据到ViewHolder(item)

总结:
RecyclerView.Recycler内部类就是用来做缓存和复用的,里面包含了ViewHolder的缓存集合ArrayList<ViewHolder>:

  1. mChangedScrap 存储单个需要刷新的item,局部刷新(屏幕内缓存,达到性能优化的目的)
  2. mAttachedScrap 存储动画(屏幕内缓存,达到性能优化的目的)
  3. mCachedViews 缓存大小最大值是2(屏幕外缓存)
  4. mViewCacheExtension 自定义扩展类,需要自己实现缓存和服用
  5. mRecyclerPool 缓存池类,里面包含了一个集合(SparseArray<ScrapData>)mScrap,缓存池的key是类型ViewType,value是ScrapData对象,ScrapData对象里面包含了集合(ArrayList<ViewHolder>)mScrapHeap,缓存池大小最大值是5(屏幕外缓存池)

猜你喜欢

转载自blog.csdn.net/tangkunTKTK/article/details/130670806
今日推荐