RecyclerView学习-RecyclerView#Adapter#notifyDataSetChanged是如何更新数据的?

简介: RecyclerView学习-RecyclerView#Adapter#notifyDataSetChanged是如何更新数据的?

想研究清楚RecyclerView#Adapter#notifyDataSetChanged是如何更新数据的,我们需要从RecyclerView#setAdapter()方法看起。

RecyclerView#setAdapter()方法:

主要是调用了RecyclerView#setAdapterInternal方法,然后调用requestLayout进行布局更新。

public void setAdapter(@Nullable Adapter adapter) {
    // bail out if layout is frozen
    setLayoutFrozen(false);
    setAdapterInternal(adapter, false, true);
    processDataSetCompletelyChanged(false);
    requestLayout();
}

RecyclerView#setAdapterInternal方法:将原有的Adapter替换为新的Adapter,同时触发对应的Listeners。
①给原来的Adapter解除与RecyclerView#mObserver的绑定。mObserverRecyclerViewDataObserver的实例。
②调用removeAndRecycleViews方法。清除mAttachedScrap
③将新的Adapter与RecyclerView#mObserver进行绑定。
④通知LayoutManagerRecyclerView相应的数据变更。

private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,
        boolean removeAndRecycleViews) {
    // 给原来的Adapter解除与RecyclerView#mObserver的绑定。mObserver是RecyclerViewDataObserver的实例。
    if (mAdapter != null) {
        mAdapter.unregisterAdapterDataObserver(mObserver);
        mAdapter.onDetachedFromRecyclerView(this);
    }
    if (!compatibleWithPrevious || removeAndRecycleViews) {
        // 清空mAttachedScrap和mChangedScrap;将mCachedViews中的ViewHolder添加到RecycledViewPool中;清空mCachedViews。
        removeAndRecycleViews();
    }
    mAdapterHelper.reset();
    final Adapter oldAdapter = mAdapter;
    mAdapter = adapter;
    if (adapter != null) {
        // 将新的Adapter与RecyclerView#mObserver进行绑定。
        adapter.registerAdapterDataObserver(mObserver);
        adapter.onAttachedToRecyclerView(this);
    }
    // 通知Layout和RecyclerView数据变更。
    if (mLayout != null) {
        mLayout.onAdapterChanged(oldAdapter, mAdapter);
    }
    mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
    mState.mStructureChanged = true;
}

接下来看一下我们的重点,Adapter是如何与RecyclerView关联起来的。

RecyclerView#Adapter#registerAdapterDataObserver(mObserver):

首先,mObserverRecyclerViewDataObserver,是RecyclerView的成员变量。

public class RecyclerView extends ViewGroup implements ScrollingView,
        NestedScrollingChild2, NestedScrollingChild3 {
    private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
}

接着看RecyclerView#Adapter#registerAdapterDataObserver方法:

public abstract static class Adapter<VH extends ViewHolder> {
    private final AdapterDataObservable mObservable = new AdapterDataObservable();
    public void registerAdapterDataObserver(@NonNull AdapterDataObserver observer) {
        mObservable.registerObserver(observer);
    }
}

AdapterDataObservable是典型的观察者模式,它是被观察者(数据发生变动的一方),继承了Observable接口:

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
    ...
}

Observable#registerObserver方法:将观察者对象添加进列表

public abstract class Observable<T> {

    protected final ArrayList<T> mObservers = new ArrayList<T>();

    public void registerObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if (mObservers.contains(observer)) {
                throw new IllegalStateException("Observer " + observer + " is already registered.");
            }
            mObservers.add(observer);
        }
    }
    ...
}

总结一下,RecyclerView#Adapter#registerAdapterDataObserver方法,会将RecyclerView中的RecyclerViewDataObserver对象mObserver当做观察者,添加到RecyclerView#Adapter中的AdapterDataObservable对象mObservable中,这样Adapter就可以作为被观察者,通知RecyclerView(观察者)数据变动了。

RecyclerView#Adapter#notifyDataSetChanged方法

接着来看下RecyclerView#Adapter#notifyDataSetChanged方法是如何更新数据的。

public final void notifyDataSetChanged() {
    mObservable.notifyChanged();
}

这样就调用到了RecyclerView#AdapterDataObservable#notifyChanged方法:

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
    public void notifyChanged() {
        // 通知每个注册的观察者,数据有变动。
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onChanged();
        }
    }
}

由于我们已经将RecyclerView#RecyclerViewDataObserver当做观察者注册给AdapterDataObservable了,所以会调用到RecyclerView#RecyclerViewDataObserver#onChanged方法:

private class RecyclerViewDataObserver extends AdapterDataObserver {
   
    @Override
    public void onChanged() {
        ...
        // 清空mCachedViews
        processDataSetCompletelyChanged(true);
        // 调用requestLayout,刷新UI
        if (!mAdapterHelper.hasPendingUpdates()) {
            requestLayout();
        }
    }
}

所以会调用到RecyclerView#processDataSetCompletelyChanged方法:给 mChildHelper 中和 mCachedViewsViewHolder添加 FLAG_UPDATEFLAG_INVALID 标记。并将mCachedViews中的ViewHolder添加到到RecycledViewPool中;清空mCachedViews

void processDataSetCompletelyChanged(boolean dispatchItemsChanged) {
    mDispatchItemsChangedEvent |= dispatchItemsChanged;
    mDataSetHasChangedAfterLayout = true;
    // 给 mChildHelper 中和 mCachedViews 的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 标记。并将mCachedViews中的ViewHolder添加到到RecycledViewPool中;清空mCachedViews
    markKnownViewsInvalid();
}

RecyclerView#markKnownViewsInvalid方法:
①给mChildHelper中的ViewHolder添加 FLAG_UPDATEFLAG_INVALID 标记
②给mCachedViews中的ViewHolder添加 FLAG_UPDATEFLAG_INVALID 标记,并将ViewHolder添加到到RecycledViewPool中;清空mCachedViews

void markKnownViewsInvalid() {
    // 给mChildHelper中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 标记
    final int childCount = mChildHelper.getUnfilteredChildCount();
    for (int i = 0; i < childCount; i++) {
        final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
        if (holder != null && !holder.shouldIgnore()) {
            holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);
        }
    }
    ...
    // 给mCachedViews中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 标记,并将ViewHolder添加到到RecycledViewPool中;清空mCachedViews
    mRecycler.markKnownViewsInvalid();
}

RecyclerView#Recycler#markKnownViewsInvalid方法:
①给 mCachedViews 中的ViewHolder添加 FLAG_UPDATEFLAG_INVALID 标记
②将mCachedViews中的ViewHolder添加到RecycledViewPool中;清空mCachedViews

void markKnownViewsInvalid() {
    // 给 mCachedViews 中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 标记
    final int cachedCount = mCachedViews.size();
    for (int i = 0; i < cachedCount; i++) {
        final ViewHolder holder = mCachedViews.get(i);
        if (holder != null) {
            holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);
            holder.addChangePayload(null);
        }
    }
    
    // 将mCachedViews中的ViewHolder添加到RecycledViewPool中;清空mCachedViews
    if (mAdapter == null || !mAdapter.hasStableIds()) {
        // we cannot re-use cached views in this case. Recycle them all
        recycleAndClearCachedViews();
    }
}

总结

1、调用RecyclerView#setAdapter()方法后:将原有的Adapter替换为新的Adapter,同时触发对应的Listeners。
①给原来的Adapter解除与RecyclerView#mObserver的绑定。mObserverRecyclerViewDataObserver的实例。
②调用removeAndRecycleViews方法。清除mAttachedScrap
③将新的Adapter与RecyclerView#mObserver进行绑定。
④通知LayoutManagerRecyclerView相应的数据变更。

2、RecyclerView#Adapter#notifyDataSetChanged方法调用后,通知RecyclerView数据变化,主要做了以下工作:
①通过观察者模式,由被观察者Adapter通知观察者RecyclerView进行对应的变更。
RecyclerView中,给 mChildHelper 中和 mCachedViewsViewHolder添加 FLAG_UPDATEFLAG_INVALID 标记。并将mCachedViews中的ViewHolder添加到到RecycledViewPool中;清空mCachedViews
③调用requestLayout刷新UI。

相关文章
|
11月前
|
编解码 人工智能 运维
南加大提出全新通用时间序列基础模型TimeDiT!基于扩散模型创新物理约束机制
 【10月更文挑战第10天】南加大提出TimeDiT模型,创新融合扩散模型与Transformer架构,针对真实世界时间序列数据的复杂性,如多分辨率、缺失值等问题,提供高效解决方案。该模型通过新颖的掩码机制和无微调编辑策略,实现多任务处理及物理知识集成,显著提升预测和异常检测的准确性和鲁棒性。
307 3
|
前端开发 Java
layui结合ajax实现下拉菜单联动效果
layui结合ajax实现下拉菜单联动效果
|
10月前
|
人工智能 Java API
ChatClient:探索与AI模型通信的Fluent API
【11月更文挑战第22天】随着人工智能(AI)技术的飞速发展,越来越多的应用场景开始融入AI技术以提升用户体验和系统效率。在Java开发中,与AI模型通信成为了一个重要而常见的需求。为了满足这一需求,Spring AI引入了ChatClient,一个提供流畅API(Fluent API)的客户端,用于与各种AI模型进行通信。本文将深入探讨ChatClient的底层原理、业务场景、概念、功能点,并通过Java代码示例展示如何使用Fluent API与AI模型进行通信。
277 8
|
消息中间件 存储 Kafka
实时计算 Flink版产品使用合集之如何实现统计同一用户最近一小时的总点击数
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
181 0
|
人工智能 安全
美欧AIGC监管政策对比
【1月更文挑战第10天】美欧AIGC监管政策对比
405 1
美欧AIGC监管政策对比
|
存储 Java 应用服务中间件
【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案
【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案
400 0
|
弹性计算 编解码 负载均衡
如何构建一套高性能、高可用性、低成本的视频处理系统?
基于函数计算和 Serverless 工作流的弹性高可用视频处理架构,充分体现了云原生时代 Serverless 化思想,以事件驱动的形式触发函数执行,真实计算资源真正意义上的按需使用。对于使用而言,这套方案在保证业务灵活度的同时,可以显著降低维护成本与资源成本,并大幅度的缩短项目交付时间。
5179 90
如何构建一套高性能、高可用性、低成本的视频处理系统?
|
芯片
带PWM 调光的线性降压 LED 恒流驱动器
一、基本概述 TX6410B是一种带 PWM 调光功能的线性降压 LED 恒流驱动器,仅需外接一个电阻就可以构成一个完整的 LED 恒流驱动电路,调节该外接电阻可调节输出电流,输出电流范围为 10~2000mA。TX6410B内置 30V 50 毫欧 MOS。TX6410B内置过热保护功能,可有效保护芯片,避免因过热而造成损坏。TX6410B具有很低的静态电流,典型值为 60uA。TX6410B带 PWM 调光功能,可通过在 DIM 脚加 PWM 信号调节 LED 电流。TX6410B采用ESOP8 封装。外露散热片接 LED 脚。 二、产品特点 内置 30V 50 毫欧 MOS 输出
299 0
|
机器学习/深度学习 人工智能 算法
机器学习PAI-Designer基础
机器学习PAI-Designer基础
450 0
|
达摩院 并行计算 TensorFlow