浅析notifyDataSetChanged内部工作流程

2023-10-29 17:20

本文主要是介绍浅析notifyDataSetChanged内部工作流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先我们知道notifyDataSetChanged是Adater的一个方法,主要用来通知ListView,告诉它Adapter的数据发生了变化,需要更新ListView的显示,所以当Adapter的数据内容改变时会调用notifyDataSetChanged()方法。
直接看看BaseAdapter中notifyDataSetChanged的源码实现,看notifyDataSetChanged是如何工作的

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {private final DataSetObservable mDataSetObservable = new DataSetObservable();public void notifyDataSetChanged() {mDataSetObservable.notifyChanged();}
}


可以看到它调用的是DataSetObservable中的notifyChanged,进入DataSetObservable查看实现

public class DataSetObservable extends Observable<DataSetObserver> {public void notifyChanged() {synchronized(mObservers) {for (int i = mObservers.size() - 1; i >= 0; i--) {mObservers.get(i).onChanged();}}}
}


其中mObervers是在DataSetObservable的父类Observable中定义:

public abstract class Observable<T> {protected final ArrayList<T> mObservers = new ArrayList<T>();}


它是一个DataSetObserver类型的ArrayList,最终执行的是DataSetObserver的onChange函数。

再来看看DataSetOberver类的源代码:

public abstract class DataSetObserver {public void onChanged() {// Do nothing}public void onInvalidated() {// Do nothing}
}


从上面的过程可以大致看出,如果需要得到ListView更新的通知,首先实现一个DataSetObserver类,重写其中的onChanged回调方法,然后把这个对象添加(注册)到ArrayList中,这样当我们调用notifyDataSetChanged的时候,它会遍历这个ArrayList取出DataSetObserver对象,回调onChanged方法。也就是说我们最终的刷新ListViewd的工作应该在这个onChanged方法中。

那么疑问就是系统在哪个地方实现了实现一个DataSetObserver类,重写其中的onChanged回调方法,然后把这个对象添加到ArrayList当中的。

其实这个工作在setAdapter中完成的,当为ListView设置一个Adapter的时候,就在这个Adapter中注册了一个回调监听,也就是上面说的实现一个DataSetObserver类,重写其中的onChanged回调方法,然后把这个对象添加到ArrayList当中,当Adapter调用notifyDataSetChanged的时候,就会回调onChanged函数,在onChanged里面进行ListView的更新,这样ListView就进行更新操作。

那么我们来看看ListAdapter中setAdapter的实现:   

@Overridepublic void setAdapter(ListAdapter adapter) {//这里判断是否已经注册了监听//如果已经注册,则取消注册//如果重复调用setAdapter,下面的代码就会执行mDataSetObserver从ArrayList中移除if (mAdapter != null && mDataSetObserver != null) {mAdapter.unregisterDataSetObserver(mDataSetObserver);}resetList();mRecycler.clear();if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);} else {mAdapter = adapter;}mOldSelectedPosition = INVALID_POSITION;mOldSelectedRowId = INVALID_ROW_ID;// AbsListView#setAdapter will update choice mode states.super.setAdapter(adapter);if (mAdapter != null) {mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();mOldItemCount = mItemCount;//得到数据的数量mItemCount = mAdapter.getCount();checkFocus();//看到没有这里定义了一个AdapterDataSetObserver,它就是DataSetObserver的实现类mDataSetObserver = new AdapterDataSetObserver();//看到这里应该明白了,这里将这个DataSetObserver实现了类对象添加到ArrayList中,这样就可以回调了mAdapter.registerDataSetObserver(mDataSetObserver);mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());int position;if (mStackFromBottom) {position = lookForSelectablePosition(mItemCount - 1, false);} else {position = lookForSelectablePosition(0, true);}setSelectedPositionInt(position);setNextSelectedPositionInt(position);if (mItemCount == 0) {// Nothing selectedcheckSelectionChanged();}} else {mAreAllItemsSelectable = true;checkFocus();// Nothing selectedcheckSelectionChanged();}//会导致调用measure()过程 和 layout()过程requestLayout();}


具体的解释直接看代码的注释,这样更方便理解,主要就是mDataSetObserver = new AdapterDataSetObserver()和mAdapter.registerDataSetObserver(mDataSetObserver)这两句,我们上面已经注释了AdapterDataSetObserver就是DataSetObserver的实现类,它重写了onChanged方法。
看AdapterDataSetObserver源代码,在这里就可以看到,notifyDatasetChanged的最终执行的操作是什么了,因为它最终回调了这个onChanged方法。AdapterDataSetObserver是AbsListView的一个内部类   

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {@Overridepublic void onChanged() {//这里是核心操作super.onChanged();if (mFastScroller != null) {mFastScroller.onSectionsChanged();}}@Overridepublic void onInvalidated() {super.onInvalidated();if (mFastScroller != null) {mFastScroller.onSectionsChanged();}}}


最终回调的就是这里的onChanged函数,直接看代码,核心操作在super.onChanged()里面。
super.onChanged意思就是执行AdapterView.AdapterDataSetObserver里面的onChanged函数,它是ApdaterView的一个内部类。   

class AdapterDataSetObserver extends DataSetObserver {private Parcelable mInstanceState = null;@Overridepublic void onChanged() {mDataChanged = true;mOldItemCount = mItemCount;mItemCount = getAdapter().getCount();// Detect the case where a cursor that was previously invalidated has// been repopulated with new data.if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null&& mOldItemCount == 0 && mItemCount > 0) {AdapterView.this.onRestoreInstanceState(mInstanceState);mInstanceState = null;} else {rememberSyncState();}checkFocus();//会导致调用measure()过程 和 layout()过程requestLayout();}@Overridepublic void onInvalidated() {mDataChanged = true;if (AdapterView.this.getAdapter().hasStableIds()) {// Remember the current state for the case where our hosting activity is being// stopped and later restartedmInstanceState = AdapterView.this.onSaveInstanceState();}// Data is invalid so we should reset our statemOldItemCount = mItemCount;mItemCount = 0;mSelectedPosition = INVALID_POSITION;mSelectedRowId = INVALID_ROW_ID;mNextSelectedPosition = INVALID_POSITION;mNextSelectedRowId = INVALID_ROW_ID;mNeedSync = false;checkFocus();requestLayout();}public void clearSavedState() {mInstanceState = null;}}


看到没有,这个类实现了DataSetObserver,正好说明了上面的说法,直接看它的onChanged函数。直接看最后一句requestLayout(),这里就会进行刷新了,
如果细心的话,你应该也会看到在setAdapter中也执行了这个函数,这样就充分说了,执行这个函数,这里是进行了布局和重绘。
这里我们可以知道一点,就是我们上面对ListView的刷新,本质就是调用了requestLayout方法。
 

这篇关于浅析notifyDataSetChanged内部工作流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/302157

相关文章

基于Python开发一个有趣的工作时长计算器

《基于Python开发一个有趣的工作时长计算器》随着远程办公和弹性工作制的兴起,个人及团队对于工作时长的准确统计需求日益增长,本文将使用Python和PyQt5打造一个工作时长计算器,感兴趣的小伙伴可... 目录概述功能介绍界面展示php软件使用步骤说明代码详解1.窗口初始化与布局2.工作时长计算核心逻辑3

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

使用JavaConfig配置Spring的流程步骤

《使用JavaConfig配置Spring的流程步骤》JavaConfig是Spring框架提供的一种基于Java的配置方式,它通过使用@Configuration注解标记的类来替代传统的XML配置文... 目录一、什么是 JavaConfig?1. 核心注解2. 与 XML 配置的对比二、JavaConf

浅析Java如何保护敏感数据

《浅析Java如何保护敏感数据》在当今数字化时代,数据安全成为了软件开发中至关重要的课题,本文将深入探讨Java安全领域,聚焦于敏感数据保护的策略与实践,感兴趣的小伙伴可以了解下... 目录一、Java 安全的重要性二、敏感数据加密技术(一)对称加密(二)非对称加密三、敏感数据的访问控制(一)基于角色的访问

Java中的内部类和常用类用法解读

《Java中的内部类和常用类用法解读》:本文主要介绍Java中的内部类和常用类用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录内部类和常用类内部类成员内部类静态内部类局部内部类匿名内部类常用类Object类包装类String类StringBuffer和Stri

Java对接Dify API接口的完整流程

《Java对接DifyAPI接口的完整流程》Dify是一款AI应用开发平台,提供多种自然语言处理能力,通过调用Dify开放API,开发者可以快速集成智能对话、文本生成等功能到自己的Java应用中,本... 目录Java对接Dify API接口完整指南一、Dify API简介二、准备工作三、基础对接实现1.

浅析如何使用xstream实现javaBean与xml互转

《浅析如何使用xstream实现javaBean与xml互转》XStream是一个用于将Java对象与XML之间进行转换的库,它非常简单易用,下面将详细介绍如何使用XStream实现JavaBean与... 目录1. 引入依赖2. 定义 JavaBean3. JavaBean 转 XML4. XML 转 J

将Java项目提交到云服务器的流程步骤

《将Java项目提交到云服务器的流程步骤》所谓将项目提交到云服务器即将你的项目打成一个jar包然后提交到云服务器即可,因此我们需要准备服务器环境为:Linux+JDK+MariDB(MySQL)+Gi... 目录1. 安装 jdk1.1 查看 jdk 版本1.2 下载 jdk2. 安装 mariadb(my

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景