android中AdapterView的观察者模式
2015-09-20 20:09
519 查看
首先介绍一下Observer类和Observable类
观察者模式中 有两个角色,通知者和观察者(被通知者),Observable可以认为是一个通知者,里面维护了一个存放观察者对象的ArrayList,DataSetObserver是一个观察者,观察者模式的目的就是当需要发生改变时,通知者会通知每个观察者做出改变,通知者与观察者是一对多的关系。
在android开发中ListView经常用到,而notifyDataSetChanged()方法常用于数据集改变的时候刷新listview,下面结合观察者模式分析一下notifyDataSetChanged实现机制。
一般我们会自定义一个adapter继承自BaseAdapter,看看BaseAdapter里面的notifyDataSetChanged
调用了DataSetObservable的notifyChanged方法,从命名上可以看出来DataSetObservable应该是个通知者
看下这两句mDataSetObserver = new AdapterDataSetObserver(); ,mAdapter.registerDataSetObserver(mDataSetObserver);也就是说每次setAdapter的时候都会把一个类型为AdapterDataSetObserver的观察者注册进去,这里的mAdapter就是BaseAdapter的实现类类型。所以notifyDataSetChanged应该就是调用AdapterDataSetObserver的onChange方法,来看看
这是一个AdapterView的内部类,最终会调用到requestLayout()方法,这是一个View类的方法,会使view重新布局。个人猜测会触发重写的getView方法所以达到刷新的作用。希望高手指正。
public abstract class DataSetObserver { /** * This method is called when the entire data set has changed, * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}. */ public void onChanged() { // Do nothing } /** * This method is called when the entire data becomes invalid, * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a * {@link Cursor}. */ public void onInvalidated() { // Do nothing } }
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>(); /** * Adds an observer to the list. The observer cannot be null and it must not already * be registered. * @param observer the observer to register * @throws IllegalArgumentException the observer is null * @throws IllegalStateException the observer is already registered */ 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); } } /** * Removes a previously registered observer. The observer must not be null and it * must already have been registered. * @param observer the observer to unregister * @throws IllegalArgumentException the observer is null * @throws IllegalStateException the observer is not yet registered */ public void unregisterObserver(T observer) { if (observer == null) { throw new IllegalArgumentException("The observer is null."); } synchronized(mObservers) { int index = mObservers.indexOf(observer); if (index == -1) { throw new IllegalStateException("Observer " + observer + " was not registered."); } mObservers.remove(index); } } /** * Remove all registered observers. */ public void unregisterAll() { synchronized(mObservers) { mObservers.clear(); } } }
观察者模式中 有两个角色,通知者和观察者(被通知者),Observable可以认为是一个通知者,里面维护了一个存放观察者对象的ArrayList,DataSetObserver是一个观察者,观察者模式的目的就是当需要发生改变时,通知者会通知每个观察者做出改变,通知者与观察者是一对多的关系。
在android开发中ListView经常用到,而notifyDataSetChanged()方法常用于数据集改变的时候刷新listview,下面结合观察者模式分析一下notifyDataSetChanged实现机制。
一般我们会自定义一个adapter继承自BaseAdapter,看看BaseAdapter里面的notifyDataSetChanged
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { private final DataSetObservable mDataSetObservable = new DataSetObservable(); public boolean hasStableIds() { return false; } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * 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方法,从命名上可以看出来DataSetObservable应该是个通知者
public class DataSetObservable extends Observable<DataSetObserver> { /** * Invokes {@link DataSetObserver#onChanged} on each observer. * Called when the contents of the data set have changed. The recipient * will obtain the new contents the next time it queries the data set. */ 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(); } } }果然,遍历了Observable中的ArrayList,逐个调用onChange方法,就像之前说的一样,观察者逐个做出改变。至于如何改变,看看ListView的setAdapter方法。
@Override 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(); }
看下这两句mDataSetObserver = new AdapterDataSetObserver(); ,mAdapter.registerDataSetObserver(mDataSetObserver);也就是说每次setAdapter的时候都会把一个类型为AdapterDataSetObserver的观察者注册进去,这里的mAdapter就是BaseAdapter的实现类类型。所以notifyDataSetChanged应该就是调用AdapterDataSetObserver的onChange方法,来看看
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(); requestLayout(); }
这是一个AdapterView的内部类,最终会调用到requestLayout()方法,这是一个View类的方法,会使view重新布局。个人猜测会触发重写的getView方法所以达到刷新的作用。希望高手指正。
相关文章推荐
- Android动画控件之Animation
- Android开发中Eclispe相关问题及相应解决
- ubuntu14.04下android Sdk manager使用代理方法总结
- Android 学习第17课,使用文件的数据存储(4种存储模式)
- Android基础学习之Tab控件
- 我的Android设计模式(二) 观察者模式
- openssl for android使用
- Android自定义ViewGroup
- Android中的onActivityResult和setResult方法的使用
- [Android] 高效加载大图、多图解决方案,有效避免程序OOM
- android中dx、dp、dip、sp单位的区别
- Android 4.4(KitKat)中的设计模式-Graphics子系统
- android 上传/下载 图片
- Android中AIDL及其使用
- Android studio使用问题(持续更新)
- Android基础学习之GridView控件
- 探讨Android中的内置浏览器和Chrome
- 录制Android屏幕Gif的方法
- Android PopupWindow使用之地区、学校选择二级联动
- 使用CheckBox