基于RxJava的Android事件分發(fā)--QxBus

前言:在實現(xiàn)這個事件分發(fā)的時候也考慮過EventBus,因為種種原因沒有采用,但是項目有個事件分發(fā)又非常方便,于是乎有了自己寫個Bus的想法,之所以使用RxJava是考慮到RxAndroid簡直不要太好用,各種線程間的切換如絲般順滑,我們做Android開發(fā)的時候切換線程比較麻煩,索性給他改造一下就是個很簡單的事件分發(fā)工具。

首先要知悉,這個工具只是我在做一個項目的時候偶然頭腦發(fā)熱搞出來的小玩意,沒什么技術(shù)含量(連構(gòu)思帶實現(xiàn)一共才用了半天時間),不知道在大型項目上運行會出現(xiàn)什么未知的BUG,分享僅作為個人筆記和經(jīng)驗交流,如對您的項目有幫助,榮幸之至,反之請一笑置之;

特性:
支持同時向多個類發(fā)送數(shù)據(jù),在多個類里定義一樣的tag即可
基于RxJava,所以線程切換于RxJava、RxAndroid一致
除了可以發(fā)送數(shù)據(jù),還可以主動向注冊事件的位置獲取數(shù)據(jù)
代碼少

開始:首先要引入RxJava和RxAndroid(無版本要求)

    //RxJava
    implementation 'io.reactivex.rxjava2:rxjava:2.2.6'
    //RxAndroid
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'

然后。。。。。直接去文章末尾復(fù)制代碼吧,200多行代碼

使用方法:

發(fā)送數(shù)據(jù)

1.在基類中根據(jù)生命周期解綁

    @Override
    protected void onDestroy() {
        super.onDestroy();
        QxBus.getInstance().unregister(this);
    }

2.在任意位置注冊,String可以更換任意指定類型(基礎(chǔ)類型不可以),但對應(yīng)tag的發(fā)送消息也需要是同類型,否則會導(dǎo)致崩潰

        QxBus.subscribe(this, tag, new QxBus.BusObserver<String>() {
            @Override
            public void onNext(@NotNull String s) {
                ToastUtils.show(s);
            }
        });

3.在任意位置發(fā)送消息

        QxBus.post(tag, "登錄成功");
獲取數(shù)據(jù)

1.在合適位置訂閱一個獲取數(shù)據(jù)的監(jiān)聽

        QxBus.subGet(this, "tag", new QxBus.OnGetDataListener<String>() {
            @Override
            public String data() {
                return "獲取數(shù)據(jù)成功";
            }
        });

2.在使用數(shù)據(jù)的位置調(diào)用get

        QxBus.get("tag", new QxBus.BusObserver<String>() {
            @Override
            public void onNext(@NotNull String s) {
                ToastUtils.show(s);
            }
        });

所以只要tag保持一致,就可以正常發(fā)送和接收數(shù)據(jù);
不過要時刻注意,因為使用了粗暴的泛型,同名的tag標簽的發(fā)送和接收對象必須是同類型,否則直接崩潰沒商量,tag就是個字符串,多定義一些,防止兩個不同邏輯使用同一個tag就不會出錯


/**
 * Author: 蕭清軒
 * Date  : 2022/10/14
 * Dest  : 基于RxJava封裝的事件分發(fā)總線
 */
public class QxBus {
    private static volatile QxBus client;

    private final Map<String, Map<String, BusObserver<Object>>> map;
    private final Map<String, Map<String, OnGetDataListener<Object>>> getMap;

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

    private QxBus() {
        map = new HashMap<>();
        getMap = new HashMap<>();
    }

    /**
     * 訂閱
     *
     * @param obj         類
     * @param tag         標簽
     * @param busObserver 觀察者
     * @param <T>         接收類型
     */
    public static <T> void subscribe(Object obj, String tag, BusObserver<T> busObserver) {
        getInstance().register(obj, tag, busObserver);
    }

    public <T> void register(Object obj, String tag, BusObserver<T> busObserver) {
        if (obj == null || busObserver == null) return;
        String objKey = obj.getClass().getName();
        Map<String, BusObserver<Object>> busMap;
        if (map.containsKey(objKey)) {
            busMap = map.get(objKey);
            if (busMap == null) {
                busMap = new HashMap<>();
            }
        } else {
            busMap = new HashMap<>();
        }
        busMap.put(tag, (BusObserver<Object>) busObserver);
        map.put(objKey, busMap);
    }

    /**
     * 解綁
     * 清除所有 obj類名下的標簽,使之失效(偽生命周期)
     *
     * @param obj 對應(yīng)類  unregister(this)
     */
    public void unregister(Object obj) {
        if (obj == null) return;
        String tag = obj.getClass().getName();
        map.remove(tag);
    }

    /**
     * 發(fā)送消息
     *
     * @param subscribeOn 發(fā)送線程
     * @param observeOn   目標線程
     * @param tag         標記
     * @param t           對象
     */
    private <T> void send(Scheduler subscribeOn, Scheduler observeOn, String tag, T t) {
        for (Map<String, BusObserver<Object>> busMap : map.values()) {
            if (busMap != null && busMap.containsKey(tag)) {
                BusObserver<T> busObserver = (BusObserver<T>) busMap.get(tag);
                if (busObserver != null)
                    Observable.create((ObservableOnSubscribe<T>) emitter -> {
                        emitter.onNext(t);
                    }).subscribeOn(subscribeOn)
                            .observeOn(observeOn)
                            .subscribe(busObserver);
            }
        }
    }

    /**
     * 開放方法 發(fā)送消息
     * 簡化{@link #send(Scheduler, Scheduler, String, Object)} 的調(diào)用
     * 最常用的方法,向訂閱指定標簽的位置發(fā)送數(shù)據(jù)
     *
     * @param tag  消息標簽
     * @param data 數(shù)據(jù)
     * @param <T>  對象類型
     */
    public static <T> void post(String tag, T data) {
        post(Schedulers.io(), tag, data);
    }

    /**
     * 向主線程發(fā)送消息
     */
    public static <T> void post(Scheduler subscribeOn, String tag, T data) {
        post(subscribeOn, AndroidSchedulers.mainThread(), tag, data);
    }

    /**
     * 向任意指定線程發(fā)送消息
     *
     * @param subscribeOn 發(fā)送線程
     * @param observeOn   接收線程
     */
    public static <T> void post(Scheduler subscribeOn, Scheduler observeOn, String tag, T data) {
        getInstance().send(subscribeOn, observeOn, tag, data);
    }

    /**
     * 訂閱一個主動獲取數(shù)據(jù)的方法
     * 和post方法剛好相反,這里是提供數(shù)據(jù),如AActivity 跳轉(zhuǎn)到 BActivity,在BActivity 中通過點擊某個按鈕
     * 獲取AActivity中的數(shù)據(jù),可以在AActivity中訂閱一個 subscribeGet 方法,
     * 通過 OnGetDataListener.data()的返回值提供數(shù)據(jù)
     * 對應(yīng)獲取數(shù)據(jù)的方法為 {@link #getData(String, BusObserver)}
     *
     * @param tag      標簽
     * @param listener 監(jiān)聽器
     * @param <T>      數(shù)據(jù)類型
     */
    public <T> void subscribeGet(Object obj, String tag, OnGetDataListener<T> listener) {
        if (obj == null || listener == null) return;
        String objKey = obj.getClass().getName();
        Map<String, OnGetDataListener<Object>> dataMap;
        if (getMap.containsKey(objKey)) {
            dataMap = getMap.get(objKey);
            if (dataMap == null) {
                dataMap = new HashMap<>();
            }
        } else {
            dataMap = new HashMap<>();
        }
        dataMap.put(tag, (OnGetDataListener<Object>) listener);
        getMap.put(objKey, dataMap);
    }

    /**
     * {@link #subscribeGet(Object, String, OnGetDataListener)} 的開放方法
     */
    public static <T> void subGet(Object obj, String tag, OnGetDataListener<T> listener) {
        getInstance().subscribeGet(obj, tag, listener);
    }

    /**
     * 獲取數(shù)據(jù)
     * 意在主動獲取數(shù)據(jù)
     * 對應(yīng)注冊方法為{@link #subscribeGet(Object, String, OnGetDataListener)}
     *
     * @param tag         標簽
     * @param busObserver 數(shù)據(jù)觀察者
     * @param <T>         數(shù)據(jù)類型
     */
    public <T> void getData(String tag, BusObserver<T> busObserver) {
        if (busObserver == null) return;
        Observable.create((ObservableOnSubscribe<T>) emitter -> {
            OnGetDataListener<T> listener = null;
            for (Map<String, OnGetDataListener<Object>> dataMap : getMap.values()) {
                if (dataMap != null && dataMap.containsKey(tag)) {
                    listener = (OnGetDataListener<T>) dataMap.get(tag);
                }
            }
            if (listener != null) {
                emitter.onNext(listener.data());
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(busObserver);
    }

    /**
     * {@link #getData(String, BusObserver)} getData的開放方法
     */
    public static <T> void get(String tag, BusObserver<T> busObserver) {
        getInstance().getData(tag, busObserver);
    }


    /**
     * 自定義觀察者 簡化版的{@link Observable}
     */
    public abstract static class BusObserver<T> implements Observer<T> {
        @Override
        public void onSubscribe(@NotNull Disposable d) {

        }

        @Override
        public void onNext(@NotNull T t) {

        }

        @Override
        public void onError(@NotNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    }

    /**
     * 獲取數(shù)據(jù)的接口,意在簡化 {@link ObservableOnSubscribe} 的操作方式
     *
     * @param <T> 數(shù)據(jù)類型
     */
    public static interface OnGetDataListener<T> {
        T data();
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容