笔记:RecycleVew绘制及缓存

recyclerView的measure、layout、draw
  1. onMeasure:三种情况
  • (1)mLayout为空,会走默认测量,但是不会显示(原因:layout中mLayout==null会return)
  • (2)开启了自动测量,dispatchLayoutStep1,dispatchLayoutStep2(),Step2可能走两次,说明布局在measure阶段已经布好。
  • (3)没有开自动测量,情况少,会走LayoutManager的onMeasure

**** State.STEP_START: mState.mLayoutStep默认值,表示未进行step1,step1后变为STEP_LAYOUT
**** STEP_LAYOUT: step1已经执行完,出于layout阶段,会调用step2测量子View,step2后变STEP_ANIMATIONS
**** ANIMATIONS:执行动画阶段,可以step3,后变为step_start。

**** dispatchLayoutStep1:预布局方法(1)处理Adapter更新(2)决定是否执行ItemAnimator(3)保存itemView的动画信息,recyclerView第一次加载数据不会执行动画
**** dispatchLayoutStep2:item的测量绘制,内部调用adapter.getItemCount()、mLayout.onLayoutChildren(),子类实现,最终决定布局策略。
**** dispatchLayoutStep3:执行step1中保存的动画,ItemAnimator,将状态改为step_start.

  1. onLayout
    内部会判断是否需要执行dispatchLayoutStep1、dispatchLayoutStep2,最终都会执行step3

  2. draw
    (1)super.draw©,1将children绘制分发给ViewGroup,2分割线绘制给ItemDecoration。会回掉到onDraw()
    (2)调onDrawOver,在每个item上绘制东西;
    (3)如RecyclerView设置setClipToPadding 每个Item可滑动到padding区

recyclerView的复用、回收
  1. 首次绘制item会把ViewHolder存到mAttachedScrap中
    LinnerLayoutManager.onLayoutChildren();
    -detachAndScrapAttachedViews()
    这里还有fill();

  2. 滚动复用-滚出去的View会被保存到mCacheViews中,如果满了,保存到RecyclerViewPool中

    滚动也会调用到innerLayoutManager.onLayoutChildren()内部调用fill(),这个方法主要处理从缓存中获取View以及缓存被划出去的View
    【1】创建新View(填充一项):先创建新的View通过layoutChunk()->layoutState.next()->recycler.getViewForPosition()->recycler.tryGetViewHolderForPositionByDeadline(),最终拿到View,到layoutChunk()->addView(),最终中添加到recycleView中
    tryGetViewHolderForPositionByDeadline方法为读取缓存的主要实现方法;

    • 根据情况通过Position从mChangedScrap中取ViewHolder (hasStableIds通过Id匹配)
    • 通过Position从mAttachedScrap、(移出屏幕的试图中,主要用mChildHelper)、mCachedViews中取
    • 通过ItemViewType
      1.如果hasStableIds ,通过type与Id从mAttachedScrap
      2.自定义缓存mViewCacheExtension不为空,从中获取View,通过View获取ViewHolder
      3.从RecycledViewPool中通过viewType获取,【通过ViewType从mScrap(SparseArray)中取ScrapData,data中有mScrapHeap(ArrayList)】,会重置数据,所以一定会bindViewHolder()
      4.通过ItemViewType调用mAdapter.createViewHolder创建View
    • 判断是否需要绑定(如果没有绑定过数据 或 需要更新 或 无效 且没有被移除时绑定表项数据)数据tryBindViewHolderByDeadline中调用adapter.bindViewHolder()
    • 获取LayoutParams设置给ViewHolder中的ItemView,将holder保存到Params中

** 1、当成功从mCachedViews中获取ViewHolder对象后,还需要对其索引进行判断,这就意味着 mCachedViews中缓存的ViewHolder只能复用于指定位置 ,打个比方:手指向上滑动,列表向下滚动,第2个表项移出屏幕,第4个表项移入屏幕,此时再滑回去,第2个表项再次出现,这个过程中第4个表项不能复用被回收的第2个表项的ViewHolder,因为他们的位置不同,而再次进入屏幕的第2个表项就可以成功复用-------
2、RecycledViewPool 中最关键的一个成员变量和两个函数。可以得出结论:RecycledViewPool中的ViewHolder存储在SparseArray中,并且按viewType分类存储(即是Adapter.getItemViewType()的返回值),同一类型的ViewHolder存放在ArrayList 中,且默认最多存储5个。
相比较于mCachedViews,从mRecyclerPool中成功获取ViewHolder对象后并没有做合法性和表项位置校验,只检验viewType是否一致。所以 从mRecyclerPool中取出的ViewHolder只能复用于相同viewType的表项。
3、mRecyclerPool中复用的ViewHolder需要重新绑定数据,从mAttachedScrap 中复用的ViewHolder不会重新创建也不需要重新绑定数据。
4、在 RecyclerView 中,并不是每次绘制表项,都会重新创建 ViewHolder 对象,也不是每次都会重新绑定 ViewHolder 数据。
5、RecyclerView 通过Recycler获得下一个待绘制表项。
6、Recycler有4个层次用于缓存 ViewHolder 对象,优先级从高到底依次为ArrayList mAttachedScrap、ArrayList mCachedViews、ViewCacheExtension mViewCacheExtension、RecycledViewPool mRecyclerPool。如果四层缓存都未命中,则重新创建并绑定 ViewHolder 对象。
7、RecycledViewPool 对 ViewHolder 按viewType分类存储(通过SparseArray),同类 ViewHolder 存储在默认大小为5的ArrayList中。
8、从mRecyclerPool中复用的 ViewHolder 需要重新绑定数据,从mAttachedScrap 中复用的 ViewHolder 不需要重新创建也不需要重新绑定数据。
9、从mRecyclerPool中复用的ViewHolder ,只能复用于viewType相同的表项,从mCachedViews中复用的 ViewHolder ,只能复用于指定位置的表项。
10、mCachedViews是离屏缓存,用于缓存指定位置的 ViewHolder ,只有“列表回滚”这一种场景(刚滚出屏幕的表项再次进入屏幕),才有可能命中该缓存。该缓存存放在默认大小为 2 的ArrayList中。 **

【2】缓存被划出去的ViewHolder:recycleByLayoutState()->recycleViewsFromEnd()->recycleChildren()->recycler.recycleView(view)->recycleViewHolderInternal(holder)

recycleViewHolderInternal()方法为缓存ViewHolder的主要实现方法:
- mcachedView是否已满,没满-直接放入,满了,将mcachedView中第0个取出放入RecyclerViewPool中,把当前放入mcachedView,以上如果失败,直接放入RecyclerViewPool中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值