Recycler(4) - 性能保证、复用机制源码解析2

写在前面,由于本人表达能力原因,之前阶段的视频后期会重新录制。
此后视频质量肯定会越来越好


在上一章RecyclerView(4)- 核心、Recycler复用机制_1 中遗留了几个问题,这一篇文章就是为了解决上篇文章遗留的问题。

目录如下:

· 1、得到
· 2、什么时候才会调用onBindViewHolder
· 3、Recycler 中 mChangedScrap、mAttachedScrap、mCacheViews 是如何贯穿在RecyclerVIew中的
· 4、RecyclerViewPool 解析

文章有相应的视频,视频地址链接在下方

1、得到

通过阅读本篇,你可能会得到什么?会收获到什么知识?(ps:没有收获不关我事 .!)

你会收获:
· onBindVieHolder方法在RecyclerVIew容器中的生命流程。
· 回收类Recycler回收保存都干了些什么
· RecyclerViewPool 解析,如何缓存viewHolder
· 结合上一章 贯穿RecyclerVIew一个简易的生命周期
· recyclerVIew架构图

2、onBindViewHolder 调用时间、调用场景

现有知识结合开发直觉找切入点 或者是 反向推切入点
我们想要了解 onBindViewHolder 在RecyclerView中如何被调用的,得先找到一个切入点,这个时候就要结合我们的使用情况发挥我们的想象力了,wenld这边呢 是猜想 我们的LayoutManager 在向我们RecyclerVIew拿 ViewHolder的时候应该会调用一次 onBindViewHolder,还有一个就是 我们手动刷新数据的时候。
于是有了两个切入点:RecyclerView.getViewForPosition(index)、 一个是 adapter.notifyDatasetChanged()
那么一个一个进去看吧 。

2.1、RecyclerView.getViewForPosition(index)

簡化后的代碼如下所示

getViewForPosition (int ){
    tryGetViewHolderForPositionByDeadline
}
tryGetViewHolderForPositionByDeadline(){
                        //..............
                    if (mState.isPreLayout() && holder.isBound()) {
                        // do not update unless we absolutely have to.
                        holder.mPreLayoutPosition = position;
                    } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
                        if (DEBUG && holder.isRemoved()) {
                            throw new IllegalStateException("Removed holder should be bound and it should"
                                    + " come here only in pre-layout. Holder: " + holder);
                        }
                        final int offsetPosition = mAdapterHelper.findPositionOffset(position);
                        bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
                    }
}
tryBindViewHolderByDeadline{
           mAdapter.bindViewHolder(holder, offsetPosition);
}

上面代码整理一下相等于

if (!(mState.isPreLayout() && holder.isBound())&& !holder.isBound() || holder.needsUpdate() || holder.isInvalid()){
        tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
                mAdapter.bindViewHolder(holder, offsetPosition);
                    onBindViewholder
}

可以看到 只有当 (!(mState.isPreLayout() && holder.isBound())&& !holder.isBound() || holder.needsUpdate() || holder.isInvalid())满足的时候 调用我们的onBindViewHolder方法

2.2、 adapter.notifyDatasetChanged()

整理后的代码如下

notifyDataSetChanged
     mObservable.notifyChanged();
           for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();      //mObserver -->  RecyclerViewDataObserver
                    setDataSetChangedAfterLayout        //RecyclerViewDataObserver
                        holder.addFlags(ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
                        setAdapterPositionsAsUnknown  //将 recyler 的  mCacheViews 中的 viewhOlder flags 添加一个 ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN
                        markKnownViewsInvalid();
                             holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);
                        markItemDecorInsetsDirty();
                        // 
                        //以上 都是 给 当前页面上显示的 viewHolder和 recyler.mCacheViews中的viewHolder
                        //      添加ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN、ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID 到 flags;
                        //      将layoutParams.mInsetsDirty=true;
            }
            requestLayout();            -->     onLayout(int,int,int,int)

notifyDataSetChanged先会将当前页面上所显示的VIewHolder以及 Recycler.mCacheViews 内的viewHolder 属性添加ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN、ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID 然后再去调用 requestLayout() -> layoutManager.onLayoutChildren() 最终会调用我们的 onBindViewHolder方法。

Paste_Image.png

2.3、 总结

  1. onBindVIewHolder 在 getViewForPosition()-> tryGetViewHolderForPositionByDeadline ->tryBindViewHolderByDeadline 被调用;
  2. 需要满足条件(!(mState.isPreLayout() && holder.isBound())&& !holder.isBound() || holder.needsUpdate() || holder.isInvalid())
  3. viewHolder如果是从以下条件下拿到的,才会去执行onBindVIewHolder
    onCreateVIewHolder()拿到
    或者是从 RecyclerViewPool中获取到的
    或者是从 recycler.mCacheVIews 中获取到 且 viewHolder的 flagsNeedUpdates||InValid 情况下

3、Recycler

Recycler顾名思义 回收的意思,通过查看它的源码 wenld发现 它真的是做 回收view相关工作的类。** /惊喜/惊喜/惊喜**
我们去探索一下它是怎么工作的吧。
文章视频地址:链接:http://pan.baidu.com/s/1o7Ai48E 密码:98pc

4、RecyclerViewPool

RecyclerViewPool功能:用来缓存 多种ItemType VIewHolder列表。
文章视频地址:链接:http://pan.baidu.com/s/1o7Ai48E 密码:98pc

Paste_Image.png

· RecyclerView(1)- Decoration源码解析
· RecyclerView(2)- 自定义Decoration打造时光轴效果
· RecyclerView(3)- LayoutMagager源码解析,LinearLayoutManager
· RecyclerView(4)- 核心、Recycler复用机制_1
· RecyclerView(4)- 核心、Recycler复用机制_2
· RecyclerView(5)- 自定义LayoutManager(布局、复用)
· RecyclerView(6)- 自定义ItemAnimator
· RecyclerView(7)- ItemTouchHelper
· RecyclerView(8)- MultiTypeAdapter文章MultiTypeAdapter Github地址
文章视频地址:链接:http://pan.baidu.com/s/1hssvXC4 密码:18v1


希望我的文章不会误导在观看的你,如果有异议的地方欢迎讨论和指正。
如果能给观看的你带来收获,那就是最好不过了。

人生得意须尽欢, 桃花坞里桃花庵
点个关注呗,对,不信你点试试?

推荐阅读更多精彩内容