文档章节

Android 设计模式 之 观察者模式

李光正
 李光正
发布于 2015/10/15 14:53
字数 1846
阅读 12
收藏 0
点赞 0
评论 0
  1. /* 
  2.  * 观察者模式 
  3.  *      定义对象间的一种一个(Subject)对多(Observer)的依赖关系,当一个对象的状态发送改变时,所以依赖于它的 
  4.  * 对象都得到通知并被自动更新 
  5.  *  
  6.  * 当然,MVC只是Observer模式的一个实例。Observer模式要解决的问题为: 
  7.  * 建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候, 
  8.  * 依赖这个“一”的多也能够同步改变。最常见的一个例子就是:对同一组数据进行统计分析时候, 
  9.  * 我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。 
  10.  * 这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。 
  11.  * Observer模式就是解决了这一个问题。 
  12.  *  
  13.  * 适用性: 
  14.  *      1. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面 
  15.  *      将这两者封装成独立的对象中以使它们可以各自独立的改变和服用 
  16.  *  
  17.  *      2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变 
  18.  *  
  19.  *      3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁 
  20.  *  
  21.  * 参与者: 
  22.  *      1. Subject(目标) 
  23.  *      目标知道它的观察者,可以有任意多个观察者观察同一个目标 
  24.  *      提供注册和删除观察者对象的接口 
  25.  *  
  26.  *      2. Observer(观察者) 
  27.  *      为那些在目标发生改变时需获得通知的对象定义个更新的接口 
  28.  *  
  29.  *      3. ConcreteSubject(具体目标) 
  30.  *      将有关状态存入各ConcreteObserver对象 
  31.  *      当它的状态发送改变时,向它的各个观察者发出通知 
  32.  *  
  33.  *      4. ConcreteObserver(具体观察者) 
  34.  *      维护一个指向ConcreteObserver对象的引用 
  35.  *      存储有关状态,这些状态应与目标的状态保持一致 
  36.  *      实现Observer的更新接口是自身状态与目标的状态保持一致 
  37.  *       
  38.  *  
  39.  * */  

有空我将把UML图补上。


下面看看Android使用到的观察者模式.

观察者(DataSetObserver),目标(Observable<T>),具体目标(DataSetObserverable)

Observer(观察者),DataSetObserver抽象2个方法,一个是观察数据改变的方法,一个是观察数据变成无效(或者不可用)时的方法。

源码路径:framework/base/core/java/android/database/DataSetObserver.java

  1. package android.database;  
  2.   
  3. /** 
  4.  * Receives call backs when a data set has been changed, or made invalid. The typically data sets 
  5.  * that are observed are {@link Cursor}s or {@link android.widget.Adapter}s. 
  6.  * DataSetObserver must be implemented by objects which are added to a DataSetObservable. 
  7.  */  
  8. public abstract class DataSetObserver {  
  9.     /** 
  10.      * This method is called when the entire data set has changed, 
  11.      * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}. 
  12.      */  
  13.     public void onChanged() {  
  14.         // Do nothing  
  15.     }  
  16.   
  17.     /** 
  18.      * This method is called when the entire data becomes invalid, 
  19.      * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a 
  20.      * {@link Cursor}. 
  21.      */  
  22.     public void onInvalidated() {  
  23.         // Do nothing  
  24.     }  
  25. }  

Subject(目标),Observable<T>是一个泛型的抽象类,主要功能是注册和撤销observer。

源码路径:framework/base/core/java/android/database/Observable.java

  1. package android.database;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. /** 
  6.  * Provides methods for (un)registering arbitrary observers in an ArrayList. 
  7.  */  
  8. public abstract class Observable<T> {  
  9.     /** 
  10.      * The list of observers.  An observer can be in the list at most 
  11.      * once and will never be null. 
  12.      */  
  13.     protected final ArrayList<T> mObservers = new ArrayList<T>();  
  14.   
  15.     /** 
  16.      * Adds an observer to the list. The observer cannot be null and it must not already 
  17.      * be registered. 
  18.      * @param observer the observer to register 
  19.      * @throws IllegalArgumentException the observer is null 
  20.      * @throws IllegalStateException the observer is already registered 
  21.      */  
  22.     public void registerObserver(T observer) {  
  23.         if (observer == null) {  
  24.             throw new IllegalArgumentException("The observer is null.");  
  25.         }  
  26.         synchronized(mObservers) {  
  27.             if (mObservers.contains(observer)) {  
  28.                 throw new IllegalStateException("Observer " + observer + " is already registered.");  
  29.             }  
  30.             mObservers.add(observer);  
  31.         }  
  32.     }  
  33.   
  34.     /** 
  35.      * Removes a previously registered observer. The observer must not be null and it 
  36.      * must already have been registered. 
  37.      * @param observer the observer to unregister 
  38.      * @throws IllegalArgumentException the observer is null 
  39.      * @throws IllegalStateException the observer is not yet registered 
  40.      */  
  41.     public void unregisterObserver(T observer) {  
  42.         if (observer == null) {  
  43.             throw new IllegalArgumentException("The observer is null.");  
  44.         }  
  45.         synchronized(mObservers) {  
  46.             int index = mObservers.indexOf(observer);  
  47.             if (index == -1) {  
  48.                 throw new IllegalStateException("Observer " + observer + " was not registered.");  
  49.             }  
  50.             mObservers.remove(index);  
  51.         }  
  52.     }  
  53.       
  54.     /** 
  55.      * Remove all registered observer 
  56.      */  
  57.     public void unregisterAll() {  
  58.         synchronized(mObservers) {  
  59.             mObservers.clear();  
  60.         }          
  61.     }  
  62. }  


ConcreateSubject(具体目标),实现的方法同Oberver一样,只不过它是通知ArrayList<Observer>下的每个Oberver去执行各自的action。

源码路径:framework/base/core/java/android/database/DataSetObservable.java

  1. package android.database;  
  2.   
  3. /** 
  4.  * A specialization of Observable for DataSetObserver that provides methods for 
  5.  * invoking the various callback methods of DataSetObserver. 
  6.  */  
  7. public class DataSetObservable extends Observable<DataSetObserver> {  
  8.     /** 
  9.      * Invokes onChanged on each observer. Called when the data set being observed has 
  10.      * changed, and which when read contains the new state of the data. 
  11.      */  
  12.     public void notifyChanged() {  
  13.         synchronized(mObservers) {  
  14.             // since onChanged() is implemented by the app, it could do anything, including  
  15.             // removing itself from {@link mObservers} - and that could cause problems if  
  16.             // an iterator is used on the ArrayList {@link mObservers}.  
  17.             // to avoid such problems, just march thru the list in the reverse order.  
  18.             for (int i = mObservers.size() - 1; i >= 0; i--) {  
  19.                 mObservers.get(i).onChanged();  
  20.             }  
  21.         }  
  22.     }  
  23.   
  24.     /** 
  25.      * Invokes onInvalidated on each observer. Called when the data set being monitored 
  26.      * has changed such that it is no longer valid. 
  27.      */  
  28.     public void notifyInvalidated() {  
  29.         synchronized (mObservers) {  
  30.             for (int i = mObservers.size() - 1; i >= 0; i--) {  
  31.                 mObservers.get(i).onInvalidated();  
  32.             }  
  33.         }  
  34.     }  
  35. }  

ConcreateObserver(具体观察者),具体观察者的任务是实实在在执行action的类,一般由开发者根据实际情况,自己实现。android也有实现的例子

源码路径:

framework/base/core/java/android/widget/AbsListView.java

  1. class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {  
  2.     @Override  
  3.     public void onChanged() {  
  4.         super.onChanged();  
  5.         if (mFastScroller != null) {  
  6.             mFastScroller.onSectionsChanged();  
  7.         }  
  8.     }  
  9.   
  10.     @Override  
  11.     public void onInvalidated() {  
  12.         super.onInvalidated();  
  13.         if (mFastScroller != null) {  
  14.             mFastScroller.onSectionsChanged();  
  15.         }  
  16.     }  
  17. }  


framework/base/core/java/android/widget/AdapterView.java
  1. class AdapterDataSetObserver extends DataSetObserver {  
  2.   
  3.     private Parcelable mInstanceState = null;  
  4.   
  5.     @Override  
  6.     public void onChanged() {  
  7.         mDataChanged = true;  
  8.         mOldItemCount = mItemCount;  
  9.         mItemCount = getAdapter().getCount();  
  10.         if (DBG) {  
  11.             Xlog.d(TAG, "AdapterView onChanged: mOldItemCount = " + mOldItemCount  
  12.                     + ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()  
  13.                     + ",AdapterView = " + AdapterView.thisnew Throwable("onChanged"));  
  14.         }  
  15.   
  16.         // Detect the case where a cursor that was previously invalidated has  
  17.         // been repopulated with new data.  
  18.         if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null  
  19.                 && mOldItemCount == 0 && mItemCount > 0) {  
  20.             AdapterView.this.onRestoreInstanceState(mInstanceState);  
  21.             mInstanceState = null;  
  22.         } else {  
  23.             rememberSyncState();  
  24.         }  
  25.         checkFocus();  
  26.         requestLayout();  
  27.     }  
  28.   
  29.     @Override  
  30.     public void onInvalidated() {  
  31.         mDataChanged = true;  
  32.           
  33.         if (DBG) {  
  34.             Xlog.d(TAG, "AdapterView onInvalidated: mOldItemCount = " + mOldItemCount  
  35.                     + ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()  
  36.                     + ",AdapterView = " + AdapterView.thisnew Throwable("onInvalidated"));  
  37.         }  
  38.   
  39.         if (AdapterView.this.getAdapter().hasStableIds()) {  
  40.             // Remember the current state for the case where our hosting activity is being  
  41.             // stopped and later restarted  
  42.             mInstanceState = AdapterView.this.onSaveInstanceState();  
  43.         }  
  44.   
  45.         // Data is invalid so we should reset our state  
  46.         mOldItemCount = mItemCount;  
  47.         mItemCount = 0;  
  48.         mSelectedPosition = INVALID_POSITION;  
  49.         mSelectedRowId = INVALID_ROW_ID;  
  50.         mNextSelectedPosition = INVALID_POSITION;  
  51.         mNextSelectedRowId = INVALID_ROW_ID;  
  52.         mNeedSync = false;  
  53.   
  54.         checkFocus();  
  55.         requestLayout();  
  56.     }  
  57.   
  58.     public void clearSavedState() {  
  59.         mInstanceState = null;  
  60.     }  
  61. }  

实例:

型运用是大家熟悉的BaseAdapter,BaseAdapter关联了一个DataSetObservable对象,并实现registerDataSetObserver和unregisterDataSetObserver两个方法实现注册和撤销Observer,方法notifyDataSetChanged间接调用Observer的实现者的onChange()方法,以达到通知数据改变的作用。使用ListView和BaseAdapter组合时,当BaseAdapter的item改变时,我们经常会调用notifyDataSetChanged(),通知Listview刷新。

但是,但是,但是,我们从来没有调用BaseAdapter的registerDataSetObserver(DataSetObserver observer)注册Observer,那么Listview如何接收到通知,并执行刷新动作呢?

我们来看看ListView做了什么

  1. /** 
  2.  * Sets the data behind this ListView. 
  3.  * 
  4.  * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter}, 
  5.  * depending on the ListView features currently in use. For instance, adding 
  6.  * headers and/or footers will cause the adapter to be wrapped. 
  7.  * 
  8.  * @param adapter The ListAdapter which is responsible for maintaining the 
  9.  *        data backing this list and for producing a view to represent an 
  10.  *        item in that data set. 
  11.  * 
  12.  * @see #getAdapter()  
  13.  */  
  14. @Override  
  15. public void setAdapter(ListAdapter adapter) {  
  16.     if (mAdapter != null && mDataSetObserver != null) {  
  17.         mAdapter.unregisterDataSetObserver(mDataSetObserver);  
  18.     }  
  19.   
  20.     resetList();  
  21.     mRecycler.clear();  
  22.   
  23.     if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {  
  24.         mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);  
  25.     } else {  
  26.         mAdapter = adapter;  
  27.     }  
  28.   
  29.     mOldSelectedPosition = INVALID_POSITION;  
  30.     mOldSelectedRowId = INVALID_ROW_ID;  
  31.   
  32.     // AbsListView#setAdapter will update choice mode states.  
  33.     super.setAdapter(adapter);  
  34.   
  35.     if (mAdapter != null) {  
  36.         mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();  
  37.         mOldItemCount = mItemCount;  
  38.         mItemCount = mAdapter.getCount();  
  39.         checkFocus();  
  40.   
  41.         mDataSetObserver = new AdapterDataSetObserver();  
  42.         mAdapter.registerDataSetObserver(mDataSetObserver);  
  43.   
  44.         mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());  
  45.   
  46.         int position;  
  47.         if (mStackFromBottom) {  
  48.             position = lookForSelectablePosition(mItemCount - 1false);  
  49.         } else {  
  50.             position = lookForSelectablePosition(0true);  
  51.         }  
  52.         setSelectedPositionInt(position);  
  53.         setNextSelectedPositionInt(position);  
  54.   
  55.         if (mItemCount == 0) {  
  56.             // Nothing selected  
  57.             checkSelectionChanged();  
  58.         }  
  59.     } else {  
  60.         mAreAllItemsSelectable = true;  
  61.         checkFocus();  
  62.         // Nothing selected  
  63.         checkSelectionChanged();  
  64.     }  
  65.   
  66.     requestLayout();  
  67. }  
注意下面3行
  1. mAdapter = adapter;  
  1. mDataSetObserver = new AdapterDataSetObserver();  
  2. mAdapter.registerDataSetObserver(mDataSetObserver);  
当我们setAdapter(ListAdapter adapter)时,BaseAdapter同时注册了AdapterDataSetObserver(),至于AdapterDataSetObserver是如何通知Listvew和每个子item刷新(invalidate)的,这里涉及到的内容已经超出文章的范围,具体请查看源码。


其实,Android用到DataSetObserver的地方很多,Cursor,WebView,Adapter,...非常之多。

本文转载自:http://blog.csdn.net/liguangzhenghi/article/details/8076369

共有 人打赏支持
李光正
粉丝 5
博文 64
码字总数 0
作品 0
大兴
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho
04/09
0
0
Android 网络编程 目录

Android 网络编程 目录 Android 网络编程1 Http协议 to be continued... Android 架构师之路 目录 Android 架构师之路1 UML图之用例图 Android 架构师之路2 UML图之类图 Android 架构师之路3...

香沙小熊
06/21
0
0
ListView 数据与UI更新机制之观察者模式

之前有一篇文章专门介绍观察者模式知识,当时通过EventBus来进行分析。近日在读《Android源码设计模式解析与实战》,看到书中介绍ListView中使用到观察者模式。为了加深对观察者模式的理解,...

Tifkingsly
07/13
0
0
Android 架构师9 设计模式之策略模式

前言 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们之间可以相互替换。这些策略算法是相同行为的不同实现。 需求 三国故事中,刘备要到江东娶孙权的妹妹孙尚香,由于这行...

zhang_pan
04/26
0
0
设计模式2——Factory设计模式

Factory工厂设计模式为创建对象提供了一种抽象,而对使用者屏蔽了对象创建的具体细节过程,工厂模式有三种:简单工厂模式,抽象工厂模式和工厂方法模式。 1. 简单工厂模式: 又叫静态工厂模式...

小米米儿小
2013/12/05
0
0
Java 设计模式(14) —— 复合模式

一、复合模式 模式常一起使用,组合在一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式,能解决一般性或一系列的问题 二、示例 本次设计模式讲解中无代码示例,由于复合模式是...

磊_lei
05/26
0
0
android与模式:单例模式

这是我们最常见的一类模式,对这一类模式有一个通用的特点就是: 封装创建的方式和过程。 这里所谓封装就是隐藏的意思,对对象的创建方法和过程不可见,或者是虚拟的过程。 隐藏创建方式,就...

今幕明
2014/03/12
0
0
《Android深入透析》之常用设计模式经验谈

前言: Android开发的设计模式,基本设计思想源于java的设计模式,java的设计模式有N多种,据不完全统计,迄今为止,网络出现最频繁的大概有23种。Java只是一门开发语言,学会并掌握这门语言...

朵朵和糖糖
2014/11/12
0
8
(一)Android中的单例模式

作为一个Android开发的老司机,或者刚入行的司机,我觉得你还是有必要学习下Android的单例模式,毕竟 单例模式是我们很常用的一个设计模式。 1. 介绍 1.1 定义 确保某一个类只有一个实例,而...

24K男
04/25
0
0
android 设计模式的应用

1 职责链模式 职责链模式的意图为:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。使...

小克898
2014/08/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
54分钟前
2
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
1
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
2
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
1
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
今天
1
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
今天
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
1
0
Dubbo解析(六)-服务调用

当dubbo消费方和提供方都发布和引用完成后,第四步就是消费方调用提供方。 还是以dubbo的DemoService举例 -- 提供方<dubbo:application name="demo-provider"/><dubbo:registry address="z...

青离
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部