生活中我们常认定某些人很有才,但什么是有才呢?明朝的王守仁曾这样解释:才,是所谓天理,应用到物上,便成了才。凡事凡物,只要掌握了所谓科学的方法,并能灵活运用,那么你也可以成为一个有才的人。

观察者模式是软件设计都会运用到的一种模式,无论何种预言,由于本人是android猿类,所以本篇仅探讨android中的观察者模式,为了详致地阐述这一模式,本文分为三个部分:概念、简单实现、android中listview的具体实现。看完这三部分,相信您自己也能够驾轻就熟地在自己的软件中编写观察者模式了。

每逢花晨月夕,便有丝竹管弦之兴,美文就要来袭了:)

一、概念

  • 定义 观察者模式是由一个发送者(发送者是笔者自己的称呼,觉较之被观察者贴切得多)和一个观察者构成的、发送者在状态改变时(用户操作、程序主动改变等)主动通知所有观察者作相应的刷新。
  • 作用 面向对象的设计原则之一就是特定的对象干特定的事,比如眼睛对象和大脑对象 ,眼睛只需负责看,将看到的信息传给大脑,大脑只负责根据 接收到的信息作出对应的反应。观察者模式提供了良好的解耦。
  • 理论实现 观察者模式定义了对象之间一对多的的依赖关系,以便一个对象的状态发生改变时,所有依赖于他的对象都能够得到通知,并自动刷新。ps:这句话是复制的,如果你看得似是而非,请带着疑问看完简单实现部分就明白了。
  • 成员介绍 观察者:(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。                 被观察者:被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者
  • 图示

二、简单实现

依照图示,上代码:首先是observer的接口类

 
/**
* Created by 笑飞 on 2016/4/28.
* 观察者,需要应用观察者模式时要实现此接口
*/
public interface Observer {
void onUpdate();
}
 

其次是observer的实现类

 
/**
* Created by 笑飞 on 2016/4/28.
*/
public class ConcreteObserver implements Observer {
private String myOnlyAttr;
private int changeCount;
/*刷新自己*/
@Override
public void onUpdate() {
myOnlyAttr = "通知Observer刷新了:"+(changeCount++)+"次";
} public String getMyOnlyAttr() {
return myOnlyAttr;
}
}
 

其次是subject的祖宗类

 
/**
* Created by 笑飞 on 2016/4/28.
* 发送者,需要应用观察者模式时的被观察者要继承此类
*/
public abstract class Subject {
/*将一个被观察者对象和多个观察者对象绑定起来*/
protected List<Observer> observers = new ArrayList<>();
/*添加观察者,我们可能需要各种各样的观察者*/
public void attachObserver(Observer observer){
if (null ==observer){
throw new NullPointerException();
}
if (!observers.contains(observer)){
observers.add(observer);
}
}
public void detachObserver(Observer observer){
if (null ==observer){
throw new NullPointerException();
}
if (observers.contains(observer)){
observers.remove(observer);
}
}
public abstract void notifyObserverUpdate();
}
 

其次是subject的实现类:

*
* Created by 笑飞 on 2016/4/28.
* 实现了刷新方法
*/
public class ConcreteSubject extends Subject {
@Override
public void notifyObserverUpdate() {
for (Observer observer :observers){
observer.onUpdate();
}
}
}
 

然后是activity的测试部分

 
public class MainActivity extends AppCompatActivity {
private ConcreteSubject subject;
private TextView textView;
ConcreteObserver observer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
observer = new ConcreteObserver();
subject = new ConcreteSubject();
/*绑定观察者*/
subject.attachObserver(observer);
}
public void update(View v){
/*通知观察者刷新*/
subject.notifyObserverUpdate();
textView.setText(observer.getMyOnlyAttr());
}
}
 

在开始第三部分之前,我们要注意,如果把上面的observer换成listview,把subject换成adapter,是不是我们经常看到和用到的listview的用法?其实 listview内置了observer,而adpter中内置了subject,换言之,listview和adapter其实就是观察者与被观察者的“形象代言人”。

好了,接下啦让我们以android中的经典ArrayAdapter来开始第三部分的分析吧!

三、android中listview的具体实现

  • listview中的observer
 
 public void setAdapter(ListAdapter adapter) {

        if (null != mAdapter) {
mAdapter.unregisterDataSetObserver(mDataSetObserver); // 关键的成员变量,继承自AbsListView,等下去看看AbsListView关于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;
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver); // 在这里进行注册,注册为发送者adapter的观察者
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();
}
if (mChoiceMode != CHOICE_MODE_NONE &&
mAdapter.hasStableIds() &&
mCheckedIdStates == null) {
mCheckedIdStates = new LongSparseArray<Boolean>();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
if (mCheckStates != null) {
mCheckStates.clear();
}
if (mCheckedIdStates != null) {
mCheckedIdStates.clear();
}
requestLayout();
}
}
 

mDataSetObserver这个观察者在AbsListView中:

AdapterDataSetObserver mDataSetObserver; // mDataSetObserver就是在这里定义的。那我们再看看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;
checkSelectionChanged();
checkFocus();
requestLayout();
}
public void clearSavedState() {
mInstanceState = null;
}
}
 
  • ArrayAdapter中的subject(发送者,google大神命名为Observable,较为贴切)

在ArrayAdapter中:

 
    @Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged(); // 关键代码,这个notifyDataSetChanged()是从父类BaseAdapter继承过来的,所以看看在父类中它干了些什么
mNotifyOnChange = true;
}
 

然后在BaseAdapter中:

 
 private final DataSetObservable mDataSetObservable = new DataSetObservable();
//这对方法用来注册或注销从属ArrayAdapter的观察者,从此以后,adapter就成了发送者(Observable)的代理人
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
  mDataSetObservable.notifyChanged();  // 关键代码:说明调的是成员变量mDataSetObservable的方法,所以进入DataSetObservable看看具体是如何操作的
}
 
 

接下来看发送者和发送者的祖宗,是不是很熟悉了?请自行与第二部分的发送者对应:

 
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) {
for (DataSetObserver observer : mObservers) { // 这里的mObservers是哪来的呢?继续追踪,但首先可以判断是来自Observable<DataSetObserver>的。进入看看
observer.onChanged();
}
}
}
/**
* Invokes onInvalidated on each observer. Called when the data set being monitored
* has changed such that it is no longer valid.
*/
public void notifyInvalidated() {
synchronized (mObservers) {
for (DataSetObserver observer : mObservers) {
observer.onInvalidated();
}
}
}
}
 
 
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>();
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();
}
}
}
 

总结:观察者模式看起来很高大上,其实说白了就是一个类维护了另一个类的一个集合,并通过这个集合绑定解绑或调用另一个类的方法,只不过,在设计底层框架时候,利用了多态的特性抽象出了接口和抽象类,以便适用于各种场合。其实在做终端页面时候完全用不到,因为多态只能增加运行时开销。然而,设置一个庞大系统时候,这种设计模式在面向对象的编程语言,可谓不能不用的手段了。

android中的所谓观察者模式的更多相关文章

  1. Android中观察者模式的升入理解

    以前对Java中的观察者模式只知道一点皮毛,在接触Android的过程中,逐渐认识到观察者模式是如此的重要,android中许多地方都用到了观察者模式例如ContentResolver操作,来总结一下 ...

  2. Android开发学习之路-Android中使用RxJava

    RxJava的核心内容很简单,就是进行异步操作.类似于Handler和AsyncTask的功能,但是在代码结构上不同. RxJava使用了观察者模式和建造者模式中的链式调用(类似于C#的LINQ). ...

  3. [Android]GOF23种设计模式 & Android中的设计模式

    GOF23种设计模式 设计原则: 1. 单一职责原则(SRP):就一个类而言,应该仅有一个引起它变化的原因 2. 开放-封闭原则(OCP):软件实体(类.模块.函数等)应该可以扩展,但是不可修改.即对 ...

  4. 系统剖析Android中的内存泄漏

    [转发]作为Android开发人员,我们或多或少都听说过内存泄漏.那么何为内存泄漏,Android中的内存泄漏又是什么样子的呢,本文将简单概括的进行一些总结. 关于内存泄露的定义,我可以理解成这样 没 ...

  5. 那些Android中的性能优化

    性能优化是一个大的范畴,如果有人问你在Android中如何做性能优化的,也许都不知道从哪开始说起. 首先要明白的是,为什么我们的App需要优化,最显而易见的时刻:用户say,什么狗屎,刷这么久都没反应 ...

  6. Android中使用反应式编程RxJava

    GitHut 地址: https://github.com/ReactiveX/RxAndroid (1)RxJava简介: RxJava 是一个在Java虚拟机上实现的响应式扩展库:提供了基于obs ...

  7. Android中你应该知道的设计模式

    建造者模式 建造者模式最明显的标志就是Build类,而在Android中最常用的就是Dialog的构建,Notification的构建也是标准的建造者模式. 建造者模式很好理解,如果一个类的构造需要很 ...

  8. 《Android源代码设计模式解析》读书笔记——Android中你应该知道的设计模式

    断断续续的,<Android源代码设计模式解析>也看了一遍.书中提到了非常多的设计模式.可是有部分在开发中见到的几率非常小,所以掌握不了也没有太大影响. 我认为这本书的最大价值有两点,一个 ...

  9. Android中MVC模型(复合模式)

    mvc是model,view,controller的缩写,mvc包括三个部分: 1.模型(model)对象:是应用程序的主体部分,全部的业务逻辑都应该写在该层. 2.视图(view)对象:是应用程序中 ...

随机推荐

  1. CS001: 清理浮动的几种方法以及对应规范说明

    以下内容转自 http://www.w3help.org/zh-cn/casestudies/001 <!==================> 前言 浮动 Floats 是 CSS 中的 ...

  2. phpeclipse常用快捷键

    phpeclipse常用快捷键

  3. ffplay 中filter的使用

    添加字幕:ffplay -vf drawtext="fontfile=arial.ttf: text='Test Text': x=100: y=300: \ fontsize=48: fo ...

  4. Android核心分析 之二方法论探讨之概念空间篇

    方法论探讨之概念空间篇 我们潜意识就不想用计算机的方式来思考问题,我们有自己的思维描述方式,越是接近我们思维描述方式,我们越容易接受和使用.各种计算机语言,建模工具,不外乎就是建立一个更接近人的思维方 ...

  5. awk过滤统计不重复的行

    awk以‘\t’为分隔符区分列 cat logs | grep IconsendRedirect | grep 1752 | awk -F'\t' '{print $8}'| wc -l awk过滤统 ...

  6. ssh2框架搭建

    原文:ssh2框架搭建 struts2+spring4.0+hibernate4.0 4.x版本与3.x版本有较大区别,要配置方法须要注意,用到的jar包如下 文件结构 src/application ...

  7. Js 日期操作

    Js获取当前日期时间及其它操作var myDate = new Date();myDate.getYear();        //获取当前年份(2位)myDate.getFullYear();    ...

  8. Android APP安全评估工具 Drozer - 使用介绍

    一.列出drozer当前可用的所有模块dz> list dz> list app.activity.forintent Find activities that can handle th ...

  9. opencv 人脸识别 (一)训练样本的处理

    本文实现基于eigenface的人脸检测与识别.给定一个图像数据库,进行以下步骤: 进行人脸检测,将检测出的人脸存入数据库2 对数据库2进行人脸建模 在测试集上进行recognition   本篇实现 ...

  10. 《Java编程那点事儿》读书笔记(一)——基本数据结构

    觉得自己记忆力很烂的样子,读书不做笔记就好像没读一样,所以决定以后读技术类的书籍,都要做好笔记. 1.IP地址和域名:如果把IP地址类比成身份证号的话,域名就是持证人的名字. 2.端口:规定一个 设备 ...