在BaseAdapter源码中了解观察者模式
来源:互联网 发布:周扬青淘宝店铺货源 编辑:程序博客网 时间:2024/05/17 23:32
转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/76146635
本文出自:【顾林海的博客】
前言
观察者模式也叫发布订阅模式,它是定义如下:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。适用的适用场景主要有关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系;事件多级触发场景;跨系统的消息交互场景,如消息队列、事件总线的处理机制。比如现在非常主流的EventBus, RxJava等框架就是采用的观察者模式。
类图说明
观察者模式的通用类图如下:
Subject被观察者,定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。
Observer观察者,观察者接受到消息后,即更新操作,对接收到的信息进行处理。
ConcreteSubject具体的被观察者,定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
ConcreteObserver具体的观察者,每个观察在接收到消息后的处理反应是不同,各个观察者自己的处理逻辑。
日常案例
在日常中比如订阅新闻邮件就是一种典型的观察者模式,用户邮箱是观察者,新闻网站是被观察者,一旦新闻网站有新闻更新,会通知用户并给用户邮箱发送新闻。
创建新闻的实体类NewsBean:
/** * 新闻实体类 */public class NewsBean { public String title; public String info;}
创建观察者(Email)接口:
public interface EmailObserver<T> { void update(T news);}
创建观察者(Email)具体实现类:
public class Email implements EmailObserver<NewsBean> { private String user; public Email(String user) { this.user = user; } @Override public void update(NewsBean news) { System.out.println("尊敬的" + user + "用户,收到一封新闻邮件,标题为:" + news.title); }}
创建被观察者(新闻网站)抽象类:
public abstract class NewObservable<T> { private List<EmailObserver> observers = new ArrayList<>(); public void registerObserver(EmailObserver observer) { if (!observers.contains(observer)) { observers.add(observer); } } public void unregisterObserver(EmailObserver observer) { if (observers.contains(observer)) { observers.remove(observer); } } public void notifyObserver(T t) { for (EmailObserver emailObserver : observers) { emailObserver.update(t); } } public void clearAllObserver() { observers.clear(); }}
NewObservable类中提供了观察者的添加、取消以及通知操作的实现。
创建被观察者(新闻网站)的具体实现:
public class NewService extends NewObservable<NewsBean> { public void make() { NewsBean newsBean = new NewsBean(); newsBean.title = "号外,号位,某某程序员居然找到女朋友了"; newsBean.info = "新闻内容....."; notifyObserver(newsBean); }
最后在场景类中使用:
public class Client { public static final void main(String[] args) { //创建被观察者新闻网站 NewService newService = new NewService(); //创建一些观察者用户 Email user1 = new Email("用户1"); Email user2 = new Email("用户2"); Email user3 = new Email("用户3"); //将观察者添加到被观察中 newService.registerObserver(user1); newService.registerObserver(user2); newService.registerObserver(user3); //被观察者(网站)发布一则新闻 newService.make(); }}
运行结果:
尊敬的用户1用户,收到一封新闻邮件,标题为:号外,号位,某某程序员居然找到女朋友了
尊敬的用户2用户,收到一封新闻邮件,标题为:号外,号位,某某程序员居然找到女朋友了
尊敬的用户3用户,收到一封新闻邮件,标题为:号外,号位,某某程序员居然找到女朋友了
Android源码中观察者模式的使用
在平时开发中,ListView用的比较多,可以通过setAdapter(adapter)方法给ListView设置适配器,其中的BaseAdapter就是实现了观察者模式。
被观察者(BaseAdapter)
BaseAdapter 源码:
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); } /** * 通知观察者(ListView重绘当前可见区域) */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } /** * 通知观察者(ListView会重绘控件) */ public void notifyDataSetInvalidated() { mDataSetObservable.notifyInvalidated(); }}
查看BaseAdapter会发现它就是一个观察者模式,其中的DataSetObservable是一个数据集的观察者,并且在BaseAdapter源码中实现了被观察者职责方法:动态地增加、取消观察者,管理观察者并通知观察者。其中notifyDataSetChanged()方法是用于通知ListView重绘当前的可见区域,notifyDataSetInvalidated()方法用于通知ListView重绘控件。
DataSetObservable承载这被观察者的职责,查看DataSetObservable源码:
public class DataSetObservable extends Observable<DataSetObserver> { /** * 同步操作,通知观察者(这里是ListView) */ public void notifyChanged() { synchronized(mObservers) { /** * 遍历观察者,并通知 */ for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } /** * 同步操作,通知观察者(这里是ListView) */ public void notifyInvalidated() { synchronized (mObservers) { /** * 遍历观察者,并通知 */ for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onInvalidated(); } } }}
DataSetObservable内部实现了通知观察者(ListView)的方法,并继承自Observable泛型类,我们继续看Observable的源码,其实到这里大家应该能知道Observable类具体做了哪些操作,一定提供了对观察者的注册和取消注册操作,这里继承Observable泛型类时指定了具体的观察者类型是DataSetObserver,这里先提下DataSetObserver 这个观察者是在ListView某个父类中定义,其实也就很好的说明了ListView是观察者,观察实现了BaseAdapter类中的数据变化,一旦数据产生变化,通过BaseAdapter的notifyChanged()方法通知ListView的重绘。
Observable源码:
public abstract class Observable<T> { /** * 用于保存观察者的列表 */ protected final ArrayList<T> mObservers = new ArrayList<T>(); /** * 添加注册一个观察者到观察者列表中。 */ 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); } } /** * 从列表中移除(取消注册)观察者。 */ 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); } } /** * 情况所有观察者 */ public void unregisterAll() { synchronized(mObservers) { mObservers.clear(); } }}
Observable内部提供了一个用于保存观察者的列表,并提供了registerObserver(observer)方法用于注册观察到列表中,unregisterObserver(observer)方法用于从观察者列表移除一个观察者,以及unregisterAll()方法清空所有观察者。
到这里整个被观察者(BaseAdatper)已经分析完毕,这里总结一些知识点:
- BaseAdapter内部绑定了一个被观察者的数据集的类(DataSetObservable)。
- DataSetObservable内部实现了两个通知观察者的方法,分别是notifyChanged()和notifyInvalidated()方法。
- DataSetObservable继承自Observable泛型类,具体观察者对象是DataSetObserver(ListView内部实现类)。
- DataSetObservable(被观察者)提供了观察者的注册(存放在列表中)方法、取消注册(从列表中移除)以及清空所有观察者。
观察者(ListView)
在给ListView添加适配器时,会调用ListView的setAdapter(adapter)方法,接下来从ListView的setAdater(adapter)方法的具体实现进行深入:
@Overridepublic void setAdapter(ListAdapter adapter) { /** * (1)第一次为ListView设置适配器时,如果已经存在观察者,就将它移除。 */ if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); /** * (2)创建观察者。 */ mDataSetObserver = new AdapterDataSetObserver(); /** * (3)将观察者注册到被观察者中。 */ 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();}
在setAdapter一开始就会去判断观察者是否存在,如果已经存在就会取消注册,在(2)中,会创建观察者,并在(3)中添加到被观察者中,AdapterDataSetObserver定义在ListView父类中。
AbsListView内部类AdapterDataSetObserver:
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(); } }}
回到BaseAdapter中,在调用BaseAdapter的notifyChanged方法时会执行继承自Observable 泛型类的DataSetObservable中的notifyChanged()方法,在这个方法中去遍历父类中的观察者列表,并调用它们的onChanged()和onInvalidated()方法,在上面分析被观察者(BaseAdapter)时,已经知道了观察者的实例类是DataSetObserver,而AbsListView内部类AdapterDataSetObserver继承自 AdapterView内部类AdapterDataSetObserver。
AdapterView内部类AdapterDataSetObserver:
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(); } @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; }}
由于AbsListView内部类AdapterDataSetObserver重写了 AdapterView内部类AdapterDataSetObserver的onChanged()和onInvalidated()方法 。也就是说BaseAdapter的notifyChanged最终执行到ListView的父类AbsListView的内部类AdapterDataSetObserver中的onChanged()和onInvalidated()方法,查看这两个方法可以看出它们调用了父类的onChanged()和onInvalidated()方法,可以看出ListView重绘的具体实现是在AdapterView内部类AdapterDataSetObserver类中实现的,在onChanged()和onInvalidated()方法中最终调用requestLayout()方法进行ListView、GridView等AdapterView组件的重新布局。
到这里整个观察者(ListView)已经分析完毕,这里总结一些知识点:
- 通过给setAdapter(adapter)方法进行观察者的注册。
- 被观察者通过notifyChanged()方法通知观察者(AbsListView内部类 AdapterDataSetObserver中的 onChanged()和onInvalidated()方法 )进行处理。
- AdapterDataSetObserver继承自AdapterView内部类AdapterDataSetObserver,并交由它来进行AdapterView组件的重新布局。
- 在BaseAdapter源码中了解观察者模式
- 从RecyclerView的源码了解观察者模式
- ListView BaseAdapter中的观察者模式
- 设计模式(二)重温观察者模式:随便窥探一波BaseAdapter源码
- (转)ListView BaseAdapter中的观察者模式
- 在Unity3d中实现观察者模式
- 观察者模式在android中使用
- 观察者模式在Android中使用浅析
- 观察者模式及在Android源码中的应用
- Android ListView与BaseAdapter的观察者模式实现
- 仿写BaseAdapter而想到的观察者模式-----思考
- junit源码学习--观察者模式
- java源码实现观察者模式
- Android源码中的观察者模式
- javascript中观察者模式
- java中观察者模式
- Unity中观察者模式
- Android中观察者模式
- IE兼容text-align的方法
- java线程2
- 1014. 福尔摩斯的约会 (20)
- xml的DI和注解的DI
- 奥威Power-BI连锁商超BI报表分析——“品牌销售分析”
- 在BaseAdapter源码中了解观察者模式
- 反射
- 车牌号
- java让数字显示千分位
- 忘了的时候看一眼,Shape属性写的很全
- git代码撤消与回退
- 【js】pagination分页(支持首页,末页,跳转)
- 基于神经卷积网络的人脸识别
- 2017 Multi-University Training Contest