《Android源码设计模式解析与实战》读书笔记(十二)
2015-12-28 09:00
435 查看
第十二章、观察者模式
观察者模式是一个使用率非常高的模式,它最常用在GUI系统、订阅–发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。比如安卓的开源项目EventBus、Otto、AndroidEventBus等事件总线类的和RxJava响应式编程其核心都是使用观察者模式。1.定义
观察者模式是一种行为类模式,它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。2.使用场景
(1)关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。(2)事件多级触发场景。
(3)跨系统的消息交换场景,如消息队列、事件总线的处理机制。
3.简单实现
这里举一个追剧的例子,平常为了不错过最新的电视剧我们会订阅或关注这个电视剧,当电视剧更新后会第一时间推送给我们,下来就简单实现一下。抽象观察者类
[code]/** * 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己 */ public interface Observer { /** * 有更新 * * @param message 消息 */ public void update(String message); }
抽象被观察者类
[code]/** * 抽象被观察者类 */ public interface Observable { /** * 推送消息 * * @param message 内容 */ void push(String message); /** * 订阅 * * @param observer 订阅者 */ void register(Observer observer); }
具体的观察者类
[code]/** * 具体的观察者类,也就是订阅者 */ public class User implements Observer { @Override public void update(String message) { System.out.println(name + "," + message + "更新了!"); } // 订阅者的名字 private String name; public User(String name) { this.name = name; } }
具体的被观察者类
[code]/** * 具体的被观察者类,也就是订阅的节目 */ 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); } }
实现
[code]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电视剧"); } }
结果
[code]小明,xxx电视剧更新了! 小光,xxx电视剧更新了! 小兰,xxx电视剧更新了!
由上面的代码可以看出实现了一对多的消息推送,推送消息都是依赖Observer和Observable这些抽象类,而User和Teleplay完全没有耦合,保证了订阅系统的灵活性和可扩展性。
4.Android源码中的观察者模式
1.BaseAdapter
BaseAdapter我相信大家都不陌生,在ListView的适配器中我们都是继承它。下面来简单分析分析。BaseAdapter 部分代码:
[code]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); } /** * 当数据集变化时,通知所有观察者 */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); }
看看mDataSetObservable.notifyChanged()方法:
[code]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(); } } }
可以看出在mDataSetObservable.notifyChanged()中遍历所有观察者,并调用他们的onChanged(),从而告知观察者发生了什么。
那么观察者怎么来的,那就是setAdapter方法,代码如下:
[code] @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);//注册观察者 ......省略 }
AdapterDataSetObserver定义在ListView的父类AbsListView中,是一个数据集观察者,代码:
[code]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(); } } }
它由继承自AbsListView的父类AdapterView的AdapterDataSetObserver, 代码如下 :
[code]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; } }
当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数会调用所有观察者 (AdapterDataSetObserver) 的onChanged方法。这就是一个观察者模式!
5.总结
1.优点
(1)观察者和被观察者之间是抽象耦合,应对业务变化。(2)增强系统的灵活性和可扩展性。
2.缺点
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。6.参考
链接:Android 设计模式 之 观察者模式相关文章推荐
- Android Kitkat 如何让系统永久不休眠
- Android:Attribute is missing the Android namespace prefix
- android的显式提交和隐式提交
- android删除文件出错
- 欢迎使用CSDN-markdown编辑器
- android130 android启动
- Android遇到java.lang.RuntimeException: Binary XML file line #20这样的问题怎么办
- Android开发之ActionBar与DrawerLayout
- Android官方刷新组件 SwipeRefreshLayout 的使用
- [android]_[ListView的基本使用]
- [android]_[四种基本布局]
- Android开发之应用程序创建与目录结构
- android 属性动画(view普通使用 和 自定义view使用)
- 【Android】Android插件开发 —— 打开插件的Activity(代理方式)
- 捐助android-x86 项目
- 定义 Android 清单
- 真正的Android
- 基于高德地图写的不同功能的地图应用
- Android 启动界面 点击按钮跳转和3秒跳转
- Android 6.0新特性