浅析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

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

工作常用指令与快捷键

Git提交代码 git fetch  git add .  git commit -m “desc”  git pull  git push Git查看当前分支 git symbolic-ref --short -q HEAD Git创建新的分支并切换 git checkout -b XXXXXXXXXXXXXX git push origin XXXXXXXXXXXXXX

嵌入式方向的毕业生,找工作很迷茫

一个应届硕士生的问题: 虽然我明白想成为技术大牛需要日积月累的磨练,但我总感觉自己学习方法或者哪些方面有问题,时间一天天过去,自己也每天不停学习,但总感觉自己没有想象中那样进步,总感觉找不到一个很清晰的学习规划……眼看 9 月份就要参加秋招了,我想毕业了去大城市磨练几年,涨涨见识,拓开眼界多学点东西。但是感觉自己的实力还是很不够,内心慌得不行,总怕浪费了这人生唯一的校招机会,当然我也明白,毕业

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

husky 工具配置代码检查工作流:提交代码至仓库前做代码检查

提示:这篇博客以我前两篇博客作为先修知识,请大家先去看看我前两篇博客 博客指路:前端 ESlint 代码规范及修复代码规范错误-CSDN博客前端 Vue3 项目开发—— ESLint & prettier 配置代码风格-CSDN博客 husky 工具配置代码检查工作流的作用 在工作中,我们经常需要将写好的代码提交至代码仓库 但是由于程序员疏忽而将不规范的代码提交至仓库,显然是不合理的 所

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgent 支持T或# User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器