利用观察者模式(发布/订阅模式)制作一个“代替”广播的通知类

我们们通常会遇到这样一个问题,从MainActivity跳转到BActivity,在BActivity中我们做了一些操作,需要MainActivity更新界面,我们经常会用startActivityForResult来操作。但是如果是MainActivity —> ….. —>BActivity 中间跳转了多个Activity,用这个方法岂不是很复杂,当然有的朋友会在MainActivity类里面注册一个BroadcastReceiver,当需要MainActivity进行相关的操作时,只需要在BActivity里面sendBroadcast即可,当然这个办法也是可行的。但是像广播这种重量级选手,我们能不用还是尽量不用。


在这里我们将用观察者模式实现一个类似广播的通知类。

一、介绍
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。

抽象主题角色(被观察者):把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。

抽象消息订阅者角色(观察者):为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。

具体主题角色(被观察者):在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。

具体消息订阅者角色(观察者):该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

二、代码实现
1. 抽象主题角色

package com.example.observerdemo.observer;

/**
 * 被观察者
 */
public interface IObservable {

    /**
     * 向消息订阅队列添加订阅者
     */
    void deleteObserver(IObserver observer);

    /**
     * 删除指定订阅者
     */
    void addObserver(IObserver observer);

    /**
     * 通知消息订阅队列里的每一个订阅者
     * @param data  给订阅者传递的参数
     * @param flag 标示
     */
    void notifyObservers(Object data,int flag);

}

2.抽象消息订阅者

package com.example.observerdemo.observer;

/**
 * 消息订阅者(观察者)
 */
public interface IObserver {

    /**
     * 当消息发布者发布消息的时候调用该方法
     * @param observable  消息发布者
     * @param msg  发布的消息内容
     * @param flag 消息的类型标记
     */
    void onMessageReceived(IObservable observable, Object msg, int flag);

}

3.具体主题角色(被观察者)

package com.example.observerdemo.observer;

import java.util.ArrayList;
import java.util.List;

/**
 * 被观察者的具体化,该类负责给观察者发送消息
 * 参考 {@link java.util.Observable}
 */
public class EventObservable implements IObservable{

    /**
     * 存放消息订阅者
     */
    List<IObserver> observers = new ArrayList<IObserver>();

    public EventObservable() {
    }

    /**
     * 向消息订阅队列添加订阅者
     */
    @Override
    public void addObserver(IObserver observer) {
        if (observer == null) {
            throw new NullPointerException("EventObservable == null");
        }
        synchronized (this) {
            if (!observers.contains(observer)) {
                observers.add(observer);
            }
        }
    }

    /**
     * 获得订阅者的数量
     */
    public int countObservers() {
        return observers.size();
    }

    /**
     * 删除指定订阅者
     */
    @Override
    public synchronized void deleteObserver(IObserver observer) {
        observers.remove(observer);
    }

    /**
     * 删除所有订阅者.
     */
    public synchronized void deleteObservers() {
        observers.clear();
    }

    /**
     * 通知消息订阅队列里的每一个订阅者
     */
    public void notifyObservers(int flag) {
        notifyObservers(null,flag);
    }
    /**
     * 通知消息订阅队列里的每一个订阅者
     * @param data  给订阅者传递的参数
     */
    @SuppressWarnings("unchecked")
    @Override
    public void notifyObservers(Object data,int flag) {
        int size = 0;
        IObserver[] arrays = null;
        synchronized (this) {
            size = observers.size();
            arrays = new IObserver[size];
            observers.toArray(arrays);
        }
        if (arrays != null) {
            for (IObserver observer : arrays) {
                observer.onMessageReceived(this, data,flag);
            }
        }
    }

}

4.具体消息订阅者角色(观察者)

public class EventObserver  implements IObserver{
    /**
     * 重写自 IObserver 的方法
     * @param observable  消息发布者
     * @param msg  发布的消息内容
     * @param flag 消息的类型标记
     */
    @Override
    public void onMessageReceived(IObservable observable, Object msg, int flag) {
        switch (flag) {
            case ObserverHolder.STAFF_ADD:  // 添加员工
                Log.e("DEVICE_ADD", (String) msg);
                count++;
                break;
            case ObserverHolder.STAFF_DELETE:  //删除员工
                Log.e("DEVICE_DELETE", (String) msg);
                count--;
                break;
        }
        txtContent.setText("还有"+count+"位员工");
    }
}

5.接下来再写一个订阅模式管理类,方便调用

package com.example.observerdemo.observer;

/**
 * 订阅模式管理类
 */
public class ObserverHolder {

    /**
     * 添加员工
     */
    public static final int STAFF_ADD = 0;

    /**
     * 删除员工
     */
    public static final int STAFF_DELETE = 1;

    /**
     * 更改员工信息
     */
    public static final int STAFF_ALTER = 2;


    private static ObserverHolder instance;

    private EventObservable observable;

    private ObserverHolder() {
        observable = new EventObservable();
    }

    public static ObserverHolder getInstance() {
        if (instance == null) {
            synchronized (ObserverHolder.class) {
                if (instance == null) {
                    instance = new ObserverHolder();
                }
            }
        }
        return instance;
    }

    /**
     * 将消息接收者注册进来
     * (如果将Activity作为订阅者在此注册的时候,切记在onDestroy()里面移除注册,否则可能导致内存泄露)
     * @param observer
     */
    public void register(IObserver observer){
        observable.addObserver(observer);
    }

    /**
     * 将消息接收者移除注册
     */
    public void unregister(IObserver observer){
        observable.deleteObserver(observer);
    }

    /**
     * 给订阅者发生消息
     * @param data
     */
    public void notifyObservers(String data,int flag){
        observable.notifyObservers(data,flag);
    }

}

6.使用

EventObserver observer = new EventObserver();
ObserverHolder.getInstance().register(observer); //注册

ObserverHolder.getInstance().unregister(observer); //不用的时候释放注册

再看一下调用

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_add:
                ObserverHolder.getInstance().notifyObservers("添加员工",ObserverHolder.STAFF_ADD);
                break;
            case R.id.btn_delete:
                ObserverHolder.getInstance().notifyObservers("删除员工",ObserverHolder.STAFF_DELETE);
                break;
        }
    }

Demo地址:
https://code.csdn.net/chengliang0315/observerdemo/tree/master
http://download.csdn.net/detail/chengliang0315/9696796

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值