Android源码设计模式——观察者模式

本篇博客分享一下Android中常用的设计模式——观察者模式。
从本篇博客开发,只要是分享的设计模式一类的,都尽量不再用术语,尽量直接用代码表示,简洁易懂。

对于观察者模式,我们只要记住一个关键点:解耦!解耦!解耦!

观察者示例

在JDK中,内置了观察者的相关类:Observer.java 和 Observable.java;

前者是:观察者需要继承的类;后者是:被观察者需要继承的类;

示例:前段时间我相中了一款键盘,但是刚好没货了,我把这个键盘加入了我的补货通知单中,也就是说:当有货的时候,淘宝会发送推送通知我补货成功的消息。 同理:很多人跟我一样都加入了补货通知单中,我们都会收到相同的消息通知。

这个示例中,观察者就是:我们, 被观察者就是:键盘

观察者:

/**
 * FileName:PeopleObserver
 * Create By:liumengqiang
 * Description:观察者(关注断货商品的人)
 */
public class PeopleObserver implements Observer {
    private String peopleName;

    public PeopleObserver(String peopleName) {
        this.peopleName = peopleName;
    }

    @Override
    public void update(Observable o, Object arg) {
        Log.e("PeopleObserver", "你好," + peopleName + ":你关注的" + arg + "到货啦,赶快下单吧");
    }
}

被观察者:

/**
 * FileName:TaobaoProductObservable
 * Create By:liumengqiang
 * Description:淘宝内的商品
 */
public class TaobaoProductObservable extends Observable {
    public void noticeAllObserver(String goodsName) {
        setChanged();

        notifyObservers(goodsName);
    }
}

将观察者和被观察者关联起来:

        //**************Java下的观察者模式**************//
        //创建观察者
        PeopleObserver zhangsan = new PeopleObserver("张三");
        PeopleObserver lisi = new PeopleObserver("李四");
        PeopleObserver wangwu = new PeopleObserver("王五");

        //创建被观察者
        TaobaoProductObservable observable = new TaobaoProductObservable();
        observable.addObserver(zhangsan);
        observable.addObserver(lisi);
        observable.addObserver(wangwu);

        //通知观察者,货物到货了
        observable.noticeAllObserver("阿米洛键盘");

在这里插入图片描述

这里我使用的JDK提供的内置观察者类。 观察者需要继承Observer ,然后重写update方法,在该方法内可以做相应的操作。 被观察者需要继承Observable,然后键盘补货成功,需要通知订阅该键盘的人的时候,需要做两个操作:

		//设置标记为:被观察者已经改变的标记
        setChanged();
        //开始依次通知观察者。
        notifyObservers(goodsName);

整体的简单示例就是如此简单,但是我们可能疑惑了,被观察者内部notifyObservers方法到底是怎么执行的呢? 怎么发送消息给观察者的呢?

观察者源码解析

在查看源码之前,我们先理一下从订阅到发布时间的步骤,以上一个示例为例:

  1. 创建观察者,继承自Observer
  2. 创建被观察者,继承自Observer
  3. 创建观察者和被观察者,然后通过addObserver方法,执行观察者订阅被观察者操作。
  4. 最后依次执行被观察者的:setChanged,notifyObservers方法,通知观察者数据改变。

上述四步就是整个观察者从创建到订阅再到发布的流程。

现在我们看下Observable的addObserver方法:

	//同步,方法锁,防止并发
    public synchronized void addObserver(Observer o) {
        if (o == null) //空判断
            throw new NullPointerException();
        if (!obs.contains(o)) { //obs是个Vector对象
            obs.addElement(o); //将观察者添加到obs集合中
        }
    }

首先addObserver方法是个线程安全的方法;在该方法内部,首先做了Observer对象空判断,最后将Observer添加到了abs集合中。

obs是一个Vector集合,Vector和ArrayList一样都是属于集合,里面都维护了一个数组,但是最大区别就是Vector是线程安全的,里面每一个方法,基本都是同步方法。 对Vector感兴趣的,可以自行查看源码学习。

通过上述代码我们得到一点:调用addObserver方法,将Observer对象添加到了集合中。

接下来分析发布事件源码:

	// 置changed标记为:true
    protected synchronized void setChanged() {
        changed = true;
    }
    public void notifyObservers(Object arg) {
    
        Object[] arrLocal;
        // 添加锁,使代码同步
        synchronized (this) {
        	//判断数据是否改变了
            if (!hasChanged())
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }
        //遍历复制的数组,然后调用每个Observer的update的方法。
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    // 获取changed标记,由于setChanged方法置为了 True,因此:此时返回true
    public synchronized boolean hasChanged() {
        return changed;
    }

我们抛开其他的代码:只需要记住一个核心的东西,就是notifyObservers方法中遍历了Vector数组,然后调用了Observer的update的方法。

这里我实际上是有个问题的:为什么setChanged是个单独的方法呢? 为什么不把changed放在notifyObservers方法中呢? 知道的小伙伴可以分享一下,谢谢!

Android中观察者模式的应用

我们刚学习Android的适用,肯定用过ListView,ListView和BaseAdapter二者就是典型的应用了观察者模式。

如下两个方法肯定是我们闭着眼睛都能想到的:

  1. setAdapter:因为只有设置了setAdapter方法的ListView才能显示。
  2. notifyDataSetChanged:当数据源改变的时候,我们要刷新UI,此时需要调用notifySetChanged方法;

我们想先看下notifyDataSetChanged方法:

    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

里面就一句话调用mDataSetObservable的notifyChanged方法,mDataSetObservable是一个DataSetObservable对象,DataSetObserva继承自Observable对象:

public class DataSetObservable extends Observable<DataSetObserver> {
    public void notifyChanged() {
        synchronized(mObservers) {
            // 这里循环遍历mObservers集合,
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
   ....
}

在notifyChanged方法内,循环遍历了mObservers集合,执行Observer的onChanged方法, 那么mObservers集合添加数据是在父类:Observable中的:

   public void registerObserver(T observer) {
       ......
       mObservers.add(observer);
       ......
    }

    public void unregisterObserver(T observer) {
      .....
      mObservers.remove(index);
      ......
    }

那么什么之后调用了registerObserver方法呢?是在BaseAdapter的registerDataSetObserver方法中:

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

那么Adapter的registerDataSetObserver方法又是什么时候调用的呢?换句话说:Observer是什么时候注册的呢?

答案是:在setAdapter方法中。

我们使用ListView控件,肯定是要最后调用setAdapter方法:

    @Override
    public void setAdapter(ListAdapter adapter) {
      		 //创建了AdapterDataSetObserver对象
            mDataSetObserver = new AdapterDataSetObserver();
            //调用了adapter的registerDataSetObserver方法,将观察者注册到集合中.
            mAdapter.registerDataSetObserver(mDataSetObserver);
		// 重新测量绘制
        requestLayout();
    }

首先通过反推理,我们可以知道,其实AdapterDataSetObserver是一个继承自Observer的类,因为adapter的registerDataSetObserver方法接收到的参数类型是:Observer类型。

那么AdapterDataSetObserver是什么呢? 这个源码是在基类AbsListView中的。

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        .......
    }

AdapterDataSetObserver又继承自AdapterView中的AdapterDataSetObserver 类:

   class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            .....
            //重新测量绘制
            requestLayout();
        }
        ......
    }

至此整个发布数据更新流程就通了。

总结:BaseAdapter内部有一个mDataSetObservable对象,而这个对象实际上就相当于一个:被观察者,而观察者就是setAdapter的时候新建的:mDataSetObserver对象,这个对象就是一个Observer对象,当数据源发生改变的时候,会通过遍历mDataSetObservable的内部数组,执行每一个mDataSetObserver的onChanged方法。

观察者模式的优缺点:

优点:

  • 有点还是解耦了
    缺点
  • 一个被观察者,多个观察者,执行执行顺序问题,如果其中一个执行慢,那么就会直接影响之后的观察者代码运行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值