观察者模式及在Android源码中的应用
来源:互联网 发布:昆士兰it 编辑:程序博客网 时间:2024/06/05 18:43
观察者模式
观察者模式是一种行为类模式,它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
观察者模式是一个使用率非常高的模式,它最常用在GUI系统、订阅–发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。比如安卓的开源项目EventBus、Otto、AndroidEventBus等事件总线类的和RxJava响应式编程其核心都是使用观察者模式。
使用场景
- 关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
栗子
这里举一个追剧的例子,平常为了不错过最新的电视剧我们会订阅或关注这个电视剧,当电视剧更新后会第一时间推送给我们,下来就简单实现一下。
抽象观察者类
/** * 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己 */public interface Observer { /** * 有更新 * * @param message 消息 */ public void update(String message);}
抽象被观察者类
/** * 抽象被观察者类 */public interface Observable { /** * 推送消息 * * @param message 内容 */ void push(String message); /** * 订阅 * * @param observer 订阅者 */ void register(Observer observer);}
具体的观察者类
/** * 具体的观察者类,也就是订阅者 */public class User implements Observer { // 订阅者的名字 private String name; public User(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + "," + message + "更新了!"); }}
具体的被观察者类
/** * 具体的被观察者类,也就是订阅的节目 */public class Teleplay implements Observable{ private List<Observer> list = new ArrayList<Observer>();//储存订阅者 @Override public void push(String message) { for(Observer observer:list){ observer.update(message); } } @Override public void register(Observer observer) { list.add(observer); }}
实现
public class Client { public static void main(String[] args) { //被观察者,这里就是用户订阅的电视剧 Teleplay teleplay = new Teleplay(); //观察者,这里就是订阅用户 User user1 = new User("小明"); User user2 = new User("小光"); User user3 = new User("小兰"); //订阅 teleplay.register(user1); teleplay.register(user2); teleplay.register(user3); //推送新消息 teleplay.push("xxx电视剧"); }}
结果
小明,xxx电视剧更新了!小光,xxx电视剧更新了!小兰,xxx电视剧更新了!
由上面的代码可以看出实现了一对多的消息推送,推送消息都是依赖Observer和Observable这些抽象类,而User和Teleplay完全没有耦合,保证了订阅系统的灵活性和可扩展性。
Android源码中的应用
在以前,我们最常用到的控件就是ListView了,而ListView最重要的一个点就是Adapter,在我们往ListView添加数据后,我们都会调用一个方法: notifyDataSetChanged(), 这个方法就是用到了我们所说的观察者模式。
跟进这个方法notifyDataSetChanged方法,这个方法定义在BaseAdapter中,代码如下:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { // 数据集观察者 private final DataSetObservable mDataSetObservable = new DataSetObservable(); // 代码省略 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(); }}
可以发现,当数据发生变化时候,notifyDataSetChanged中会调用mDataSetObservable.notifyChanged()方法
public class DataSetObservable extends Observable<DataSetObserver> { /** * Invokes onChanged on each observer. Called when the data set being observed has * changed, and which when read contains the new state of the data. */ public void notifyChanged() { synchronized(mObservers) { // 调用所有观察者的onChanged方式 for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } }}
mDataSetObservable.notifyChanged()中遍历所有观察者,并且调用它们的onChanged方法。
那么这些观察者是从哪里来的呢?首先ListView通过setAdapter方法来设置Adapter
@Override public void setAdapter(ListAdapter adapter) { // 如果已经有了一个adapter,那么先注销该Adapter对应的观察者 if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } // 代码省略 if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; // 获取数据的数量 mItemCount = mAdapter.getCount(); checkFocus(); // 注意这里 : 创建一个数据集观察者 mDataSetObserver = new AdapterDataSetObserver(); // 将这个观察者注册到Adapter中,实际上是注册到DataSetObservable中 mAdapter.registerDataSetObserver(mDataSetObserver); // 代码省略 } else { // 代码省略 } requestLayout(); }
在设置Adapter时会构建一个AdapterDataSetObserver,最后将这个观察者注册到adapter中,这样我们的被观察者、观察者都有了。
AdapterDataSetObserver定义在ListView的父类AbsListView中,代码如下 :
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(); } } }
从代码中可看出,它继承于AdapterView的内部类AdapterDataSetObserver,代码如下:
class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; // 调用Adapter的notifyDataSetChanged的时候会调用所有观察者的onChanged方法,核心实现就在这里 @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; // 获取Adapter中数据的数量 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(); // 重新布局ListView、GridView等AdapterView组件 requestLayout(); } // 代码省略 public void clearSavedState() { mInstanceState = null; } }
可见该类确实继承于观察者抽象类DataSetObserver。
当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数会调用所有观察者 (AdapterDataSetObserver) 的onChanged方法。这就是一个观察者模式!
**总结:**AdapterView中有一个内部类AdapterDataSetObserver,在ListView设置Adapter时会构建一个AdapterDataSetObserver,并且注册到Adapter中,这个就是一个观察者。而Adapter中包含一个数据集可观察者DataSetObservable,在数据数量发生变更时开发者手动调用Adapter.notifyDataSetChanged,而notifyDataSetChanged实际上会调用DataSetObservable的notifyChanged函数,该函数会遍历所有观察者的onChanged函数。在AdapterDataSetObserver的onChanged函数中会获取Adapter中数据集的新数量,然后调用ListView的requestLayout()方法重新进行布局,更新用户界面。
- 观察者模式及在Android源码中的应用
- 观察者模式在Android中的应用
- 浅学设计模式之观察者<Observer>模式及在android中的应用
- 浅学设计模式之观察者<Observer>模式及在android中的应用 .
- 浅学设计模式之观察者<Observer>模式及在android中的应用
- 浅学设计模式之观察者<Observer>模式及在android中的应用
- 工厂方法模式及在Android源码中的应用
- Android源码中的观察者模式
- Rx框架简介,及在观察者模式中的应用
- 观察者模式(Observer)在Android中的应用:
- 策略模式及Android源码中的应用
- Android源码学习之观察者模式应用
- 观察者模式在Java编程中的应用
- 观察者模式在项目中的应用
- 观察者模式在安卓中的应用
- 观察者模式在MVP中的应用
- 观察者模式在电话中的应用
- 观察者模式在交易系统中的应用
- java入门基础-02
- Courses
- 创建maven项目时弹出错误窗口
- 1131. Subway Map (30)
- BroadCastReceiver分析
- 观察者模式及在Android源码中的应用
- Docker Registry创建自己私有仓库
- 进程同步03--Peterson算法
- 在Windows服务器上安装JDK,Tomcat,MySQL进行项目的部署运行
- nodejs核心模块-http path url querystring
- redis学习参考
- 使用js改变表格行的背景色
- Swift 【利用 泛型 便利 xib 的加载过程】
- Java代码访问Servlet并返回