LiveDataBus替代RxBus破花、EventBus

https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651748475&idx=4&sn=8feb14dd49ce79726ecf12eb6c243740&chksm=bd12a1368a652820df7c556182d3494d84ae38d4aee4e84c48c227aa5083ebf2b1a0150cf1b5&scene=38#wechat_redirect

LiveDataBus

LiveDataBus是基于LiveData實(shí)現(xiàn)的類似EventBus的消息通信框架谦趣,它是基于LiveData實(shí)現(xiàn)的.

LiveDataBus的優(yōu)點(diǎn)

  1. LiveData具有的這種可觀察性和生命周期感知的能力
  2. 使用者不用顯示調(diào)用反注冊(cè)方法,由于LiveData具有生命周期感知能力,所以LiveDataBus只需要調(diào)用注冊(cè)回調(diào)方法座每,而不需要顯示的調(diào)用反注冊(cè)方法前鹅。
  3. LiveDataBus的實(shí)現(xiàn)極其簡(jiǎn)單,相對(duì)EventBus復(fù)雜的實(shí)現(xiàn)峭梳,LiveDataBus只需要一個(gè)類就可以實(shí)現(xiàn)舰绘。
  4. LiveDataBus可以減小APK包的大小,由于LiveDataBus只依賴Android官方Android Architecture Components組件的LiveData葱椭,沒有其他依賴捂寿,本身實(shí)現(xiàn)只有一個(gè)類。

LiveDataBus的組成

  • 消息
    • 消息可以是任何的Object挫以,可以定義不同類型的消息者蠕,如Boolean窃祝、String掐松。也可以定義自定義類型的消息踱侣。
  • 消息通道
    • LiveData扮演了消息通道的角色,不同的消息通道用不同的名字區(qū)分大磺,名字是String類型的抡句,可以通過名字獲取到一個(gè)LiveData消息通道。
  • 消息總線
    • 消息總線通過單例實(shí)現(xiàn)杠愧,不同的消息通道存放在一個(gè)HashMap中待榔。
  • 訂閱
    • 訂閱者通過getChannel獲取消息通道,然后調(diào)用observe訂閱這個(gè)通道的消息流济。
  • 發(fā)布
    • 發(fā)布者通過getChannel獲取消息通道锐锣,然后調(diào)用setValue或者postValue發(fā)布消息。

LiveDataBus的具體實(shí)現(xiàn)

public final class LiveDataBus {

    private final Map<String, BusMutableLiveData<Object>> bus;

    private LiveDataBus() {
        bus = new HashMap<>();
    }

    private static class SingletonHolder {
        private static final LiveDataBus DEFAULT_BUS = new LiveDataBus();
    }

    public static LiveDataBus get() {
        return SingletonHolder.DEFAULT_BUS;
    }

    public <T> MutableLiveData<T> with(String key, Class<T> type) {
        if (!bus.containsKey(key)) {
            bus.put(key, new BusMutableLiveData<>());
        }
        return (MutableLiveData<T>) bus.get(key);
    }

    public MutableLiveData<Object> with(String key) {
        return with(key, Object.class);
    }

    private static class ObserverWrapper<T> implements Observer<T> {

        private Observer<T> observer;

        public ObserverWrapper(Observer<T> observer) {
            this.observer = observer;
        }

        @Override
        public void onChanged(@Nullable T t) {
            if (observer != null) {
                if (isCallOnObserve()) {
                    return;
                }
                observer.onChanged(t);
            }
        }

        private boolean isCallOnObserve() {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            if (stackTrace != null && stackTrace.length > 0) {
                for (StackTraceElement element : stackTrace) {
                    if ("android.arch.lifecycle.LiveData".equals(element.getClassName()) && "observeForever".equals(element.getMethodName())) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

    private static class BusMutableLiveData<T> extends MutableLiveData<T> {

        private Map<Observer, Observer> observerMap = new HashMap<>();

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            super.observe(owner, observer);
            try {
                hook(observer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void observeForever(@NonNull Observer<T> observer) {
            if (!observerMap.containsKey(observer)) {
                observerMap.put(observer, new ObserverWrapper(observer));
            }
            super.observeForever(observerMap.get(observer));
        }

        @Override
        public void removeObserver(@NonNull Observer<T> observer) {
            Observer realObserver = null;
            if (observerMap.containsKey(observer)) {
                realObserver = observerMap.remove(observer);
            } else {
                realObserver = observer;
            }
            super.removeObserver(realObserver);
        }

        private void hook(@NonNull Observer<T> observer) throws Exception {
            //get wrapper's version
            Class<LiveData> classLiveData = LiveData.class;
            Field fieldObservers = classLiveData.getDeclaredField("mObservers");
            fieldObservers.setAccessible(true);
            Object objectObservers = fieldObservers.get(this);
            Class<?> classObservers = objectObservers.getClass();
            Method methodGet = classObservers.getDeclaredMethod("get", Object.class);
            methodGet.setAccessible(true);
            Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);
            Object objectWrapper = null;
            if (objectWrapperEntry instanceof Map.Entry) {
                objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
            }
            if (objectWrapper == null) {
                throw new NullPointerException("Wrapper can not be bull!");
            }
            Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
            Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");
            fieldLastVersion.setAccessible(true);
            //get livedata's version
            Field fieldVersion = classLiveData.getDeclaredField("mVersion");
            fieldVersion.setAccessible(true);
            Object objectVersion = fieldVersion.get(this);
            //set wrapper's version
            fieldLastVersion.set(objectWrapper, objectVersion);
        }
    }
}

使用方法

  • 注冊(cè)訂閱:
LiveDataBus.get()
        .with("tag", String.class)
        .observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
            }
        });

  • 發(fā)送消息
LiveDataBus.get().with("tag").setValue(str);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绳瘟,一起剝皮案震驚了整個(gè)濱河市雕憔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌糖声,老刑警劉巖斤彼,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蘸泻,居然都是意外死亡琉苇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門悦施,熙熙樓的掌柜王于貴愁眉苦臉地迎上來并扇,“玉大人,你說我怎么就攤上這事抡诞“萋恚” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵沐绒,是天一觀的道長(zhǎng)俩莽。 經(jīng)常有香客問我,道長(zhǎng)乔遮,這世上最難降的妖魔是什么扮超? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮蹋肮,結(jié)果婚禮上出刷,老公的妹妹穿的比我還像新娘。我一直安慰自己坯辩,他們只是感情好馁龟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著漆魔,像睡著了一般坷檩。 火紅的嫁衣襯著肌膚如雪却音。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天矢炼,我揣著相機(jī)與錄音系瓢,去河邊找鬼。 笑死句灌,一個(gè)胖子當(dāng)著我的面吹牛夷陋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胰锌,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骗绕,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了资昧?” 一聲冷哼從身側(cè)響起爹谭,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎榛搔,沒想到半個(gè)月后诺凡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡践惑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年腹泌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尔觉。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凉袱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侦铜,到底是詐尸還是另有隱情专甩,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布钉稍,位于F島的核電站涤躲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏贡未。R本人自食惡果不足惜种樱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望俊卤。 院中可真熱鬧嫩挤,春花似錦、人聲如沸消恍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狠怨。三九已至约啊,卻和暖如春邑遏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棍苹。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茵汰,地道東北人枢里。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蹂午,于是被迫代替她去往敵國(guó)和親栏豺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容