notifyDataSetChanged()源码分析以及如何实现ListView局部刷新
来源:互联网 发布:js的横向时间轴源码 编辑:程序博客网 时间:2024/06/13 07:48
notifyDataSetChanged()
当我们调用BaseAdapter的NotifyDataSetChanged()时,为什么ListView会全局刷新呢?
/** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); }
其中调用了DataSetObservable的notifyChanged():
public class DataSetObservable extends Observable<DataSetObserver> { …… public void notifyChanged() { synchronized(mObservers) { // since onChanged() is implemented by the app, it could do anything, including // removing itself from {@link mObservers} - and that could cause problems if // an iterator is used on the ArrayList {@link mObservers}. // to avoid such problems, just march thru the list in the reverse order. for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } ……}
mObservers是DataSetObservable的成员变量,一个ArrayList,可以在DataSetObservable的父类Observable< T >中看出:
public abstract class Observable<T> { /** * The list of observers. An observer can be in the list at most * once and will never be null. */ protected final ArrayList<T> mObservers = new ArrayList<T>(); ……}
从以上代码可以看出notifyChanged()调用的是DataSetObserver的onChanged():
public void onChanged() { // Do nothing }
DataSetObserver是一个抽象类,onChanged()默认是空实现,那我们就试着去找它的具体子类。
猜想应该是在ListView的setAdapter()中设置了DataSetObserver的子类:
public void setAdapter(ListAdapter adapter) { 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(); mDataSetObserver = new AdapterDataSetObserver(); 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(); } requestLayout(); }
可以看到new了一个AdapterDataSetObserver,并且作为参数传进了BaseAdapter的registerDataSetObserver():
public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); }
其中调用了Observable的registerObserver():
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); } }
这里把刚才new的AdapterDataSetObserver添加到了观察者的集合中,当调用notifyDataSetChanged()时就会调用AdapterDataSetObserver的onChange():
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { @Override public void onChanged() { super.onChanged(); if (mFastScroll != null) { mFastScroll.onSectionsChanged(); } } @Override public void onInvalidated() { super.onInvalidated(); if (mFastScroll != null) { mFastScroll.onSectionsChanged(); } } }
AdapterDataSetObserver 是ListView的一个内部类,它继承自AdapterView的一个也叫AdapterDataSetObserver 内部类:
@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(); requestLayout(); }
在这里可以看到,notifyDataSetChanged()最终调用了requestLayout(),请求了View的重绘。
关于requestLayout(),可以看这篇文章View的绘制流程(Android开发艺术探索学习笔记)。
很多时候我们只要刷新ListView中的一条item即可,不用每次都notifyDataSetChanged(),因为每次对整个ListView进行重绘,很耗费性能,所以下面来介绍一下ListView的局部刷新。
其实很简单就是手动调用一下Adapter的getView(),但是还是要根据实际情况,倘若你需要刷新的这个item还没在界面上展示就没必要刷新了,因为等到它要出现在界面上的时候自然会调用getView()。下面看一下Google推荐的做法:
private void updateItem(int position) { /**第一个可见的位置**/ int firstVisiblePosition = listView.getFirstVisiblePosition(); /**最后一个可见的位置**/ int lastVisiblePosition = listView.getLastVisiblePosition(); /**在看见范围内才更新,不可见的滑动后自动会调用getView方法更新**/ if (position >= firstVisiblePosition && position <= lastVisiblePosition) { /**获取指定位置view对象**/ View view = listView.getChildAt(position - firstVisiblePosition); adapter.getView(position, view, listView); } }
参考:
1.Android源码分析之NotifyDataSetChanged()
2.Android ListView优化之局部刷新(更新)(非notifyDataSetChanged)
- notifyDataSetChanged()源码分析以及如何实现ListView局部刷新
- 如何动态刷新ListView的显示---notifyDataSetChanged
- ListView实现item局部刷新
- ListView实现Item局部刷新
- ListView实现Item局部刷新
- 如何实现局部刷新
- notifyDataSetChanged 动态刷新listview
- listview notifyDataSetChanged()刷新显示
- listview notifyDataSetChanged不刷新
- notifyDataSetChanged ListView 不刷新
- ListView中notifyDataSetChanged()刷新数据不更新原因分析
- 源码分析listview的adapter的notifyDataSetChanged方法分析
- ajax如何实现局部刷新
- Android ListView优化之局部刷新(更新)(非notifyDataSetChanged)
- ListView notifyDataSetChanged()不刷新数据
- 局部刷新ListView,实现点赞功能
- Android奇巧:ListView实现Item局部刷新
- ListView的观察者模式的应用,以及调用notifyDataSetChanged()方法时,为什么会刷新ListView
- Java和C++中“隐藏/覆盖/重写/重载” 的区别
- 第3讲 微信商城云服务器后台创建
- Linux SVN 命令详解
- Oracle+Mybatis的foreach insert批量插入报错的快速解决办法
- 逻辑回归、决策树和支持向量机(I)
- notifyDataSetChanged()源码分析以及如何实现ListView局部刷新
- 排序算法之简单选择排序
- Android实现保存图片到本地并在相册中显示
- 【算法题】小易记单词
- Java动态代理的两种实现方法
- 微信商城开发系列第四篇 不写代码玩转微信公众号
- vue新建项目(四)项目部署
- 虚拟机下搭建JDK+Tomcat+Nginx环境【三】——Nginx简单配置
- opengles开发环境搭建