組件之間的通信LiveDataBus

關於LiveDataBus

① LiveData是Android Architecture Components提出的框架。LiveData是一個能夠被觀察的數據持有 類,它能夠感知並遵循Activity、Fragment或Service等組件的生命週期。正是因爲LiveData對組件 生命週期可感知特色,所以能夠作到僅在組件處於生命週期的激活狀態時才更新UI數據。php

② LiveData須要一個觀察者對象,通常是Observer類的具體實現。當觀察者的生命週期處於STARTED或 RESUMED狀態時,LiveData會通知觀察者數據變化;在觀察者處於其餘狀態時,即便LiveData的數據變化了, 也不會通知。git

LiveData的優勢

① UI和實時數據保持一致,由於LiveData採用的是觀察者模式,這樣一來就能夠在數據發生改變時得到通知 ,更新UI。github

② 避免內存泄漏,觀察者被綁定到組件的生命週期上,當被綁定的組件銷燬(destroy)時,觀察者會馬上 自動清理自身的數據。app

③ 不會再產生因爲Activity處於stop狀態而引發的崩潰,例如:當Activity處於後臺狀態時,是不會收到 LiveData的任何事件的。框架

④ 不須要再解決生命週期帶來的問題,LiveData能夠感知被綁定的組件的生命週期,只有在活躍狀態纔會通 知數據變化。ide

⑤ 實時數據刷新,當組件處於活躍狀態或者從不活躍狀態到活躍狀態時老是能收到最新的數據。post

⑥ 解決Configuration Change問題,在屏幕發生旋轉或者被回收再次啓動,馬上就能收到最新的數據。this

爲何要用LiveDataBus替代EventBus和RxBus

① LiveDataBus的實現及其簡單,相對EventBus複雜的實現,LiveDataBus只須要一個類就能夠實現。spa

② LiveDataBus能夠減少APK包的大小,因爲LiveDataBus只依賴Android官方Android Architecture Components組件的LiveData,沒有其餘依賴,自己實現只有一個類。做爲比較,EventBus JAR包大小爲 57kb,RxBus依賴RxJava和RxAndroid,其中RxJava2包大小2.2MB,RxJava1包大小1.1MB, RxAndroid包大小9kb。使用LiveDataBus能夠大大減少APK包的大小。code

③ LiveDataBus依賴方支持更好,LiveDataBus只依賴Android官方Android Architecture Components 組件的LiveData,相比RxBus依賴的RxJava和RxAndroid,依賴方支持更好。

④ LiveDataBus具備生命週期感知,LiveDataBus具備生命週期感知,在Android系統中使用調用者不須要 調用反註冊,相比 EventBus和RxBus使用更爲方便,而且沒有內存泄漏風險。

LiveDataBus的組成

① 消息 消息能夠是任何的Object,能夠定義不一樣類型的消息,如Boolean、String。也能夠定義自定義類型的 消息。

② 消息通道 LiveData扮演了消息通道的角色,不一樣的消息通道用不一樣的名字區分,名字是String類型的,能夠通 過名字獲取到一個LiveData消息通道。

③ 消息總線 消息總線經過單例實現,不一樣的消息通道存放在一個HashMap中。

④ 訂閱 Observer 訂閱者經過getChannel獲取消息通道,而後調用observe訂閱這個通道的消息。

⑤ 發佈 setValue postValue 發佈者經過getChannel獲取消息通道,而後調用setValue或者postValue發佈消息。

訂閱註冊

LiveDataBus.get().with("MainActivity", HuaWei.class).observe(this, 
    new Observer<HuaWei>() {
              @Override
              public void onChanged(@Nullable HuaWei huaWei) {
                  if (huaWei != null)
                      Toast.makeText(MainActivity.this, huaWei.getName(),
                      Toast.LENGTH_SHORT).show();
              }
          });
複製代碼
  • 發送消息
HuaWei huaWei = new HuaWei("華爲","P30Pro");
        LiveDataBus.get().with("MainActivity",HuaWei.class).postValue(huaWei);
複製代碼

LiveDataBus原理圖

LiveDataBus 問題出現

  • 對於LiveDataBus的初版實現,咱們發現,在使用這個LiveDataBus的過程當中,訂閱者會收到訂閱以前發佈的消息。對於一個 消息總線來講,這是不可接受的。不管EventBus或者RxBus,訂閱方都不會收到訂閱以前發出的消息。對於一個消息總線, LiveDataBus必需要解決這個問題。

LiveDataBus 問題緣由總結

  • 對於這個問題,總結一下發生的核心緣由。對於LiveData,其初始的version是-1,當咱們調用了其setValue或者postValue, 其vesion會+1;對於每個觀察者的封裝ObserverWrapper,其初始version也爲-1,也就是說,每個新註冊的觀察者,其 version爲-1;當LiveData設置這個ObserverWrapper的時候,若是LiveData的version大於ObserverWrapper的version, LiveData就會強制把當前value推送給Observer

LiveDataBus 最終實現

  • LiveDataBus 實現
public final class LiveDataBus {
        
            private final Map<String, MutableLiveData<Object>> bus;
        
            private LiveDataBus() {
                bus = new HashMap<>();
            }
        
            private static class SingletonHolder {
                private static final LiveDataBus LIVE_DATA_BUS = new LiveDataBus();
            }
        
            public static LiveDataBus get() {
                return SingletonHolder.LIVE_DATA_BUS;
            }
            public synchronized <T> MutableLiveData<T> with(String key,Class<T> type){
                if (!bus.containsKey(key)){
                    bus.put(key,new BusMutableLiveData<>());
                }
                return (MutableLiveData<T>) bus.get(key);
            }
        }

複製代碼
  • LiveDataBus 反射 使observer.mLastVersion = mVersion
public class BusMutableLiveData<T> extends MutableLiveData<T> {
            @Override
            public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T>
            observer) {
                super.observe(owner, observer);
                try {
                    hook(observer);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        
            /**
             * 反射技術  使observer.mLastVersion = mVersion
             *
             * @param observer ob
             */
            private void hook(Observer<T> observer) throws Exception {
                //根據源碼 若是使observer.mLastVersion = mVersion; 就不會走回調
                OnChange方法了,因此就算註冊
                //也不會收到消息
                //首先獲取liveData的class
                Class<LiveData> classLiveData = LiveData.class;
                //經過反射獲取該類裏mObserver屬性對象
                Field fieldObservers = classLiveData.getDeclaredField("mObservers");
                //設置屬性能夠被訪問
                fieldObservers.setAccessible(true);
                //獲取的對象是this裏這個對象值,他的值是一個map集合
                Object objectObservers = fieldObservers.get(this);
                //獲取map對象的類型
                Class<?> classObservers = objectObservers.getClass(); //獲取map對象中全部的get方法 Method methodGet = classObservers.getDeclaredMethod("get", Object.class); //設置get方法能夠被訪問 methodGet.setAccessible(true); //執行該get方法,傳入objectObservers對象,而後傳入observer做爲key的值 Object objectWrapperEntry = methodGet.invoke(objectObservers, observer); //定義一個空的object對象 Object objectWrapper = null; //判斷objectWrapperEntry是否爲Map.Entry類型 if (objectWrapperEntry instanceof Map.Entry) { objectWrapper = ((Map.Entry) objectWrapperEntry).getValue(); } if (objectWrapper == null) { throw new NullPointerException("Wrapper can not be null!"); } //若是不是空 就獲得該object的父類 Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
                //經過他的父類的class對象,獲取mLastVersion字段
                Field fieldLastVersion = classObserverWrapper.getDeclaredField
                ("mLastVersion");
                fieldLastVersion.setAccessible(true);
                Field fieldVersion = classLiveData.getDeclaredField("mVersion");
                fieldVersion.setAccessible(true);
                Object objectVersion = fieldVersion.get(this);
                //把mVersion 字段的屬性值設置給mLastVersion
                fieldLastVersion.set(objectWrapper, objectVersion);
            }
        }
        
複製代碼
LiveDataBusDemo

感謝

謝謝你們的閱讀,想要了解更多,請關注我

GitHub

相關文章
相關標籤/搜索