Observer - 即观察者模式在android的正确食用方式

来源:互联网 发布:php引用 编辑:程序博客网 时间:2024/04/28 19:04

观察者模式的介绍

首先我们要弄明白,什么是观察者模式

当有一个对象,需要拥有一对多的依赖关系,当这个对象的状态或者信息出现了变动的时候,所以与之有依赖的所有对象都会获得通知并且更新。
那么这个对象就被称为被观察者,与之有依赖关系的人都被称为观察者

那么,转化为代码语言就是

//被观察者public class BeWatcher extends Observable{    ...    @Override    public void notifyObservers(Object data) {        super.notifyObservers(data);        setChanged();    }}
//观察者public class Wather implements Observer{    ...    @Override    public void update(Observable observable, Object data){        ...    }}

ok,基本上的代码形式就是这样。
但是,仅仅如此你会发现还有很多问题
例如:为什么要重载notifyObservers()方法;为什么数据没有传输过去;为什么看上去那么简单,实际上实现起来却发现非常痛苦呢。。。

没问题

接下来就是解答疑惑的时间:

首先,是为什么重载notifyObservers()

很简单,因为如果你不重载这个方法, 你会发现通知根本没有通知到
所以

    @Override    public void notifyObservers(Object data) {        //用于通知你的观察者们,被观察者已经发生了变化        super.notifyObservers(data);        setChanged();    }

当然,详细的解释如下:

首先看一下setChanged()的源码

    /**     * Sets the changed flag for this {@code Observable}. After calling     * {@code setChanged()}, {@code hasChanged()} will return {@code true}.     */    protected void setChanged() {        changed = true;    }

很简单,然后找一下谁使用changed这个值

public synchronized boolean hasChanged() {    return changed;}

notifyObservers的代码

    @SuppressWarnings("unchecked")    public void notifyObservers(Object data) {        int size = 0;        Observer[] arrays = null;        synchronized (this) {            if (hasChanged()) {                clearChanged();                size = observers.size();                arrays = new Observer[size];                observers.toArray(arrays);            }        }        if (arrays != null) {            for (Observer observer : arrays) {                observer.update(this, data);            }        }

但是为什么要加入这样一个开关呢?可能原因大致有三点

1.筛选有效通知,只有有效通知可以调用setChanged。比如,我的微信朋友圈一条状态,好友A点赞,后续该状态的点赞和评论并不是每条都通知A,只有A的好友触发的操作才会通知A。

2.便于撤销通知操作,在主题中,我们可以设置很多次setChanged,但是在最后由于某种原因需要取消通知,我们可以使用clearChanged轻松解决问题。

3.主动权控制,由于setChanged为protected,而notifyObservers方法为public,这就导致存在外部随意调用notifyObservers的可能,但是外部无法调用setChanged,因此真正的控制权应该在主题这里。

接着,是数据为什么没有传输过去更新
笔者我的遇到的问题是在SecordActivity里的BeWatcher.getInstance().deleteObservers();
这样我原本在MainActivity中的添加的BeWatcher的监听(即BeWatcher.getInstance().addObserver(this);)被清除了,所以导致MainActivity中的数据没有正常传输到SecordActivity中,而SecordActivity却能传输到MainActivity中。。

那么关于怎么稍微优化被观察者和观察者的代码呢?
在这里,我会贴出我的自己的实际项目的一些代码

被观察者ObserverUtils

/** * Created by kennychaos on 2016/8/24. * 角色:被观察者 */public class ObserverUtils extends Observable {    private static ObserverUtils utils;    private Info info = null;        public static ObserverUtils getInstance(){        if(utils == null) {            synchronized (ObserverUtils.class) {                utils = new ObserverUtils();            }        }        return utils;    }    @Override    public void notifyObservers(Object data) {        super.notifyObservers(data);        setChanged();    }}

基类BasicActivity

/** * Created by kennychaos on 2016/8/24. * 观察者模式Observer * 角色:观察者 */public abstract class BasicActivity extends Activity implements Observer{    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        initData();    }    @Override    protected void onResume(){        ObserverUtils.getInstance().addObserver(this);        super.onResume();    }    public abstract void initData();    @Override    protected void onDestroy(){        ObserverUtils.getInstance().deleteObserver(this);        super.onDestroy();    }    ...}

观察者们 实现类MainActivity (SecordActivity也是同理)

    ...    @Override    public void update(Observable observable, Object data) {        if(data instanceof Info){//对比data是否跟Info属于统一结构            final Info minfo = (Info) data;            info = minfo;            runOnUiThread(new Runnable() {                @Override                public void run() {                    Log.d("Observer",info.getValue());                    textView.setText(info.getValue());                }            });        }   }   public void initData(){       ...       //记得在进行页面跳转的时候提示其他观察者们被观察者已经发生了变化       button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                ...                ObserverUtils.getInstance().notifyObservers(info);                ...            }        });   }   ...

Ending

0 0
原创粉丝点击