Reference: http://blog.csdn.net/hp910315/article/details/47174531

首先我们知道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的实现:

    @Override
public 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 selected
checkSelectionChanged();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
} //会导致调用measure()过程 和 layout()过程
requestLayout();
}

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

    class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
//这里是核心操作
super.onChanged();
if (mFastScroller != null) {
mFastScroller.onSectionsChanged();
}
} @Override
public 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;

        @Override
public 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();
} @Override
public 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 restarted
mInstanceState = AdapterView.this.onSaveInstanceState();
} // Data is invalid so we should reset our state
mOldItemCount = 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方法。

关于requestLayout里面具体干了什么,执行流程是什么,可以看看下面这篇文章:

浅析notifyDataSetChanged内部工作流程的更多相关文章

  1. spark-Worker内部工作流程

  2. Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析

    本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象.与Google原生AOSP有些许差异.请读者知悉. ...

  3. Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程

    本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...

  4. Android 4.4 Kitkat Phone工作流程浅析(七)__来电(MT)响铃流程

    本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...

  5. 前端发展态势 && 前端工作流程个人浅析

    于在未开启cleartype的情况下,一些中文字体在非偶数字号下的显示效果欠佳,所以一般建议使用12.14.16.18.22px等偶数字号.也就 是对某个分辨率选择离它最近的偶数字号.例如:屏幕横向分 ...

  6. 浅析Linux操作系统工作的基础

    环境:lubuntu 13.04   kernel 3.9.7 作者:SA12226265 katao 简介: 本文根据 Linux™ 系统工作基础的分析,对存储程序计算机.堆栈(函数调用堆栈)机制和 ...

  7. Spark基本工作流程及YARN cluster模式原理(读书笔记)

    Spark基本工作流程及YARN cluster模式原理 转载请注明出处:http://www.cnblogs.com/BYRans/ Spark基本工作流程 相关术语解释 Spark应用程序相关的几 ...

  8. 前端工作流程自动化——Grunt/Gulp 自动化

    什么是自动化 先来说说为什么要自动化.凡是要考虑到自动化时,你所做的工作必然是存在很多重复乏味的劳作,很有必要通过程序来完成这些任务.这样一来就可以解放生产力,将更多的精力和时间投入到更多有意义的事情 ...

  9. Struts2 工作流程

    Struts2使用了WebWork的设计核心(XWork),在内部使用拦截器处理用户请求,从而允许用户业务逻辑控制器和ServletAPI分离.Struts2内部是一个MVC架构,Struts2 的核 ...

随机推荐

  1. HDU 3999 The order of a Tree (先序遍历)

    The order of a Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  2. 安装Tomcat的Apr

    转:http://www.cnblogs.com/littlehb/archive/2013/04/02/2994785.html 安装Tomcat的Apr,提升性能 发现 Tomcat 可以用 Ap ...

  3. 代码管理(一)git

    代码管理工具有很多 主要的有两个 git  和  svn svn  衍生出来的软件有   cornerstone   smartSVN git  的图形界面工具有  Sourcetree 前几年  s ...

  4. log4j(四)——如何控制不同风格的日志信息的输出?

    一:测试环境与log4j(一)——为什么要使用log4j?一样,这里不再重述 二:老规矩,先来个栗子,然后再聊聊感受 import org.apache.log4j.*; //by godtrue p ...

  5. iconv 中文截断问题的解决方法

    GB2312 转换为 UTF-8 <?php $content = iconv('GB2312', 'UTF-8', $content); // $content为字符串 ?> iconv ...

  6. Android基础之——CountDownTimer类,轻松实现倒计时功能

    在发现这个类之前,一直是用的handler,子线程发消息,UI线程进行倒计时的显示工作.前几天在做一个倒计时显示的时候发现了这个类,用起来非常方便 翻看了下源代码.内部已经帮我们实现了handler的 ...

  7. xcode修改项目名后反复出现 clang error

    xcode修改项目名后反复出现 clang error,  提示 ld: file not found . 并且该错误并不是出现在项目编译阶段,而是项目的Tests 的link阶段, 同时提示 xct ...

  8. Map和JSON的互相转换

    JSON-Lib方式 /**   * 函数注释:parseJSON2Map()<br>   * 用途:该方法用于json数据转换为<Map<String, Object> ...

  9. JPA之@GeneratedValue注解(转)

    JPA的@GeneratedValue注解,在JPA中,@GeneratedValue注解存在的意义主要就是为一个实体生成一个唯一标识的主键(JPA要求每一个实体Entity,必须有且只有一个主键), ...

  10. Caused by: org.apache.jasper.JasperException: javax.el.ELException: java.lang.IllegalAccessException: Class javax.el.BeanELResolver can not access a m

    在tomcat版本下的7.0.35没有问题. 在tomcat版本下的7.0.12出现问题.