利用觀察者模式(發佈/訂閱模式)製作一個“代替”廣播的通知類

我們們通常會遇到這樣一個問題,從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

發佈了35 篇原創文章 · 獲贊 48 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章