美文网首页
Android源码设计模式学习笔记-观察者模式

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

作者: e小e | 来源:发表于2018-01-27 22:05 被阅读3次

    观察者模式主要是用于一对多模块之间通信的解耦.
    它的基本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<DataSetObserver> {
        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源码设计模式学习笔记-观察者模式

          本文链接:https://www.haomeiwen.com/subject/yttcaxtx.html