Android源码设计模式学习笔记-观察者模式

观察者模式主要是用于一对多模块之间通信的解耦.
它的基本UML如下

image.png

Subject: 抽象主题,也就是被观察者角色,抽象主题角色把所有观察者对象的引用都保存到一个集合里,每个主题可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象.
ConcreteSubject: 具体主题,该角色将有关状态存入具体,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知,具体主题角色又叫做具体被观察者(Concrete Observable)角色
Observer: 抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得主题更改通知时更新自己
ConcreteObserver: 具体的观察者,该角色实现抽象观察者角色定义的更新接口,以便在主题的状态发生变化时更新自己的状态
下面是一个观察者模式的简单实现:
开发技术前沿网站(www.devtf.cn)是一个技术文章的网站,时常会更新新的技术文章后然后推送给订阅者,我们来看看这个简单的需求如何通过观察者模式去实现.

public class Coder implements Observer{

    public String name;

    public Coder(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Hi, "+name+" , DevTechFrontier 更新啦,内容 :"+arg);
    }

    @Override
    public String toString() {
        return "Coder{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class DevTechFrontier extends Observable {
    public void postNewPublication(String content){
        //标示状态和内容发生改变
        setChanged();
        //通知所有观察者
        notifyObservers();
    }
}
DevTechFrontier devTechFrontier = new DevTechFrontier();
Coder misimple = new Coder("mr.simple");
Coder coder1 = new Coder("coder-1");
Coder coder2 = new Coder("coder-2");
Coder coder3 = new Coder("coder-3");
devTechFrontier.addObserver(coder1);
devTechFrontier.addObserver(coder2);
devTechFrontier.addObserver(coder3);
devTechFrontier.postNewPublication("新的一起开发技术前线周报发布啦");

Observer和Observable是JDK中的内置类型,可见观察者模式是非常重要的,这里Observer是抽象的观察者角色,Coder扮演的是具体观察者角色;Observable是抽象主题角色,DevTechFrontier则是具体的主题角色。DevTechFrontier通过addObserver添加Coder到它的观察者列表中,一旦有文章更新便会通知所有列表中观察者对象.

Android中的观察者模式

ListView添加数据后,会调用Adapter的notifyDataSetChanged()方法,这是为什么呢?今天就来揭开它的神秘面纱。
第一步我们就跟进这个方法

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);
    }
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }
}

我们再跟进mDataSetObservable.notifyChanged()中去看看:

public class DataSetObservable extends Observable {
    public void notifyChanged() {
        synchronized(mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
}

调用notifyChanged后它会去通知mObservers这个观察者集合数据发生改变。这些观察者是ListView通过setAdapter方法设置Adapter产生的, 我们看看相关的代码:

   @Override
    public void setAdapter(ListAdapter adapter) {
        //如果有了一个Adapter,那么先注销该Adapter对应的观察者
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
       super.setAdapter(adapter);
        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();
            //注意这里,创建一个数据观察
            mDataSetObserver = new AdapterDataSetObserver();
            //将这个观察者注册到Adapter中,实际上是注册到mDataSetObservable中
            mAdapter.registerDataSetObserver(mDataSetObserver);
            //代码省略
        } else {
            //代码省略
        }
    }

这下我们观察者,被观察者都有了,它们怎么进行注册的也知道了,最后看看AdapterDataSetObserver到底是什么.它是AdapterView.java的一个内部类

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();
        }
}

当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数会调用所有观察者(AdapterDataSetObserver)的onChanged方法,在onChanged函数中又会调用ListView重新布局的函数使得Listview刷新界面,这就是一个观察模式.

你可能感兴趣的:(Android源码设计模式学习笔记-观察者模式)