03 LiveData實(shí)戰(zhàn)與應(yīng)用

前言

上一節(jié)內(nèi)容我們已經(jīng)充分介紹了LiveData組件,我們可以發(fā)現(xiàn)在使用LiveData分發(fā)數(shù)據(jù)的時(shí)候,是不會(huì)耦合任何Context獨(dú)享的,所以這個(gè)機(jī)制就從框架層避免了NPE,OOM等問題。但與此同時(shí)我們也發(fā)現(xiàn)了一些問題,比如LiveData無法取消黏性事件。如果之前發(fā)送的時(shí)間,而后注冊(cè)的觀察者也能接受到這條消息,那么是有可能會(huì)給我們帶來麻煩的。

本節(jié)我們就要以一種優(yōu)雅的方式去解決這個(gè)黏性事件的問題,與此同時(shí)還要基于LiveData打造一款消息分發(fā)總線,支持跨頁(yè)面的數(shù)據(jù)發(fā)送與監(jiān)聽,從而徹底拋棄EventBus。

需求分析
  • 基于LiveData組件
  • 保證內(nèi)存不會(huì)泄露
  • 不用反注冊(cè)消息總線
  • 支持黏性事件

上面幾點(diǎn)就是我們要最終實(shí)現(xiàn)的效果。用法上和EventBus非常相像,但我們的優(yōu)勢(shì)不用手動(dòng)反注冊(cè),不用擔(dān)心內(nèi)存泄露了。

HiDataBus.with("eventName").observer(lifecycleOwner,sticky,new    Observer<String>{
   void onChanged(String data){
   
   }
})
疑難解惑

消息分發(fā)核心方法:

void considerNotify(ObserverWrapper observer) {
      //觀察者沒有處于活躍狀態(tài),則不分發(fā)。
       if (!observer.shouldBeActive()) {
           observer.activeStateChanged(false);
           return;
       }
       //觀察者接收的消息的次數(shù)>=livedata發(fā)送消息的次數(shù),不分發(fā)。
       //如果之前已經(jīng)發(fā)送過數(shù)據(jù)了,新注冊(cè)的observer也能接收到最后一條數(shù)據(jù)。
       if (observer.mLastVersion >= mVersion) {
           return;
       }
  
      //根本原因在于ObserverWrapper的version字段在創(chuàng)建時(shí)=-1,沒有主動(dòng)和LiveData的mVersion字段對(duì)齊
       observer.mLastVersion = mVersion;
       observer.mObserver.onChanged((T) mData);
   }

控制黏性事件的突破口在于觀察者的version字段,我們要在注冊(cè)一個(gè)新的Observer時(shí)把它的mLastVersion字段和LiveData.mVersion字段主動(dòng)保持一致就可以了。

但是上面這個(gè)version字段我們都是拿不到也無法修改的,網(wǎng)絡(luò)上有種方案使用反射強(qiáng)行讓Observer的mLastVersion和LiveData.mVersion對(duì)齊,但是不夠優(yōu)雅。

所以我們的做法是使用代理設(shè)計(jì)模式,從而修改掉新注冊(cè)O(shè)bserver的行為,下面來看代碼:

 class StickyObserver<T> implements Observer<T> {
       private StickyLiveData<T> mLiveData;
       private Observer<T> mObserver;
       private boolean mSticky;

     //標(biāo)記該observer已經(jīng)接收幾次數(shù)據(jù)了,用以過濾老數(shù)據(jù)重復(fù)接收
     private int mLastVersion = 0;

     public StickyObserver(StickyLiveData liveData, Observer<T> observer, boolean sticky) {
             //比如先使用StickyLiveData發(fā)送了一條數(shù)據(jù)。StickyLiveData#version=1
             //那當(dāng)我們創(chuàng)建WrapperObserver注冊(cè)進(jìn)去的時(shí)候
             //需要把它的version和 StickyLiveData的version保持一致
             //用以過濾老數(shù)據(jù),否則 豈不是會(huì)收到老的數(shù)據(jù)?
               mLastVersion = mLiveData.mVersion;
            }

            @Override
            public void onChanged(T t) {
              
                if (mLastVersion >= mLiveData.mVersion) {
                    //但如果當(dāng)前observer它是關(guān)心 黏性事件的,則給他。
                    if (mSticky && mLiveData.mStickyData != null) {
                        mObserver.onChanged(mLiveData.mStickyData);
                    }
                    return;
                }

                mLastVersion = mLiveData.mVersion;
                mObserver.onChanged(t);
            }
        }

支持黏性事件訂閱、分發(fā)的StickyLiveData,自己管控消息分發(fā)的時(shí)機(jī),相比于網(wǎng)絡(luò)盛傳的使用反射修改LiveData.mVersion字段的方式優(yōu)雅的太多了

public static class StickyLiveData<T> extends LiveData<T> {
        private String mEventName;
        private T mStickyData;
        private int mVersion = 0;
        public StickyLiveData(String eventName) {
            mEventName = eventName;
      }

      @Override
      public void setValue(T value) {
          //每次發(fā)送消息,版本號(hào)就需要+1,因?yàn)槲覀冃枰ㄟ^這個(gè)version管控,要不要分發(fā)黏性事件。
          mVersion++;
          super.setValue(value);
      }

      @Override
      public void postValue(T value) {
          super.postValue(value);
      }

      public void setStickyData(T stickyData) {
          //同步的方式發(fā)送黏性消息
          this.mStickyData = stickyData;
          setValue(stickyData);
      }

      public void postStickyData(T stickyData) {
          //異步的形式發(fā)送消息
          this.mStickyData = stickyData;
          postValue(stickyData);
      }

      @Override
      public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
          observerSticky(owner, observer, false);
      }

      public void observerSticky(LifecycleOwner owner, Observer<? super T> observer, boolean sticky) {
          super.observe(owner, new WrapperObserver(this, observer, sticky));
          owner.getLifecycle().addObserver(new LifecycleEventObserver() {
              @Override
              public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                  if (event == Lifecycle.Event.ON_DESTROY) {
                      //自動(dòng)反注冊(cè)
                      mHashMap.remove(mEventName);
                  }
              }
          });
      }
}
總結(jié)

通過對(duì)LiveData的實(shí)戰(zhàn)應(yīng)用,我們?cè)僖淮戊柟塘薒iveData的消息分發(fā)機(jī)制實(shí)現(xiàn)原理。日常開發(fā)中,如果有跨頁(yè)面的消息分發(fā)需求的話已經(jīng)不需要我們?cè)僖肫渌魏慰蚣芰恕?/p>

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

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