LiveDataBus事件分發(fā)

前言

很早之前就在項目中接觸到了EventBus,覺得非常的方便,在任何地方都能注冊事件,然后在任何地方都能發(fā)送,對于多個fragment,多個activity的通訊,提供了一個非常便捷的方式。

最近接觸到了LiveData,發(fā)現(xiàn)了一種更方便的方式。在android底層就實現(xiàn)了支持,配合activity和fragment的生命周期使用。當(dāng)然并不是自己想出來的,也是看了別人的教學(xué)視頻,相當(dāng)于自己做個記錄學(xué)習(xí)下吧。

LiveDataBus的封裝

LiveDataBus其實代碼上非常的簡單。依賴的包我就不贅述了,參考下
https://developer.android.google.cn/topic/libraries/architecture/livedata

應(yīng)該很多人已經(jīng)接觸過了LiveData。我就直接貼出代碼了。

package so.dian.myapplication

import androidx.lifecycle.MutableLiveData

object LiveDataBus {

    private var liveMap = HashMap<String, MutableLiveData<*>>()

    fun <T> with(key: String): MutableLiveData<T> {
        return if (liveMap.containsKey(key)) {
            liveMap[key] as MutableLiveData<T>
        } else {
            var liveData = MutableLiveData<T>()
            liveMap[key] = liveData
            liveData
        }
    }

    fun <T> post(key: String, value: T) {
        if (liveMap.containsKey(key)) {
            (liveMap[key] as MutableLiveData<T>).postValue(value)
        }
    }
}

代碼非常的簡單,無非就是寫一個Map,保存LiveData。然后通過不同的key做區(qū)分。

如何使用

  1. 先注冊通過key
LiveDataBus.with<EventData>("key").observe(this, Observer {
            Toast.makeText(MainActivity@ this, "接收到事件 ${it.value}", Toast.LENGTH_LONG).show()
        })
  1. 在任意地方可以發(fā)送消息
LiveDataBus.post("key", EventData("test1", "aa"))

這里EventData是自己定義的數(shù)據(jù)類,你可以自己定義。

反射去除粘性效果

上面的使用方法,使用過EventBus和LiveData的同學(xué)應(yīng)該是分分鐘就能上手了,我就不過多贅述了。

使用過EventBus的同學(xué)肯定知道StickyEvent,粘性事件。而這里使用LiveDataBus其實默認(rèn)就有了粘性的效果。不知道粘性事件的同學(xué)可以先了解下。

https://www.cnblogs.com/fuyaozhishang/p/7968059.html

簡而言之就是,那么如果之前發(fā)送過粘性事件,你接下來第一次注冊事件的時候會馬上收到一條消息。那么有時候我們是不需要這樣的需求的。所以這里我們可以通過反射進(jìn)行修改。

首先我們要通過源碼先找到為何注冊的時候會收到一條前面發(fā)送過的消息。
這里我寫了一個Demo。有2個Activity。分別為MainActivity和Main2Activity。代碼如下

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        LiveDataBus.with<EventData>("key").observe(this, Observer {
            Toast.makeText(MainActivity@ this, "接收到事件 ${it.value}", Toast.LENGTH_LONG).show()
        })

        bt1.setOnClickListener {
            startActivity(Intent(MainActivity@ this, Main2Activity::class.java))
        }

        bt2.setOnClickListener {
            LiveDataBus.post("key", EventData("test1", "aa"))
        }
    }
}


class Main2Activity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        LiveDataBus.with<EventData>("key").observe(this, Observer {
            Log.e("aaaa","aaaa")
            Toast.makeText(MainActivity@ this, "Main2Activity接收到事件 ${it.value}", Toast.LENGTH_LONG).show()
        })
    }
}


image.png

先點擊發(fā)送消息,在點擊跳轉(zhuǎn),那么一進(jìn)入Main2Activity后就會接收到事件

image.png

這邊簡單的跟下代碼,不詳細(xì)的說,有興趣的人可以自己跟一下。
按步驟發(fā)現(xiàn)

  1. class MainActivity : AppCompatActivity。
  2. public class AppCompatActivity extends FragmentActivity
  3. class FragmentActivity extends ComponentActivity
protected void onCreate(@Nullable Bundle savedInstanceState) {
      ...
       ReportFragment.injectIfNeededIn(this);
      ...
   }
public class ReportFragment extends Fragment {
...
 @Override
    public void onResume() {
        ...
        dispatch(Lifecycle.Event.ON_RESUME);
    }
...
 private void dispatch(Lifecycle.Event event) {
       ...
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
          ...
...
}
public class LifecycleRegistry extends Lifecycle {
...
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        ...
        moveToState(next);
    }
...
   private void moveToState(State next) {
        ...
        sync();
       ...
    }
...
private void sync() {
        ...
                backwardPass(lifecycleOwner);
           ...
    }
...
  private void backwardPass(LifecycleOwner lifecycleOwner) {
            ...
                observer.dispatchEvent(lifecycleOwner, event);
             ...
        }
    }
...
}
 static class ObserverWithState {
void dispatchEvent(LifecycleOwner owner, Event event) {
          ...
            mLifecycleObserver.onStateChanged(owner, event);
           ...
        }
}
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
   public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
           ...
            activeStateChanged(shouldBeActive());
        }
...
void activeStateChanged(boolean newActive) {
           ...
                dispatchingValue(this);
            ...
        }
...
void dispatchingValue(@Nullable ObserverWrapper initiator) {
       ....
                    considerNotify(iterator.next().getValue());
         ...
    }
...
private void considerNotify(ObserverWrapper observer) {
       ....
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
...
}

好,到這里就結(jié)束了,簡單來說呢就是observer.mLastVersion<mVersion,所以觸發(fā)了onChange事件。只要利用反射把observer.mLastVersion==mVersion就成了。

先說明下原因。
mVersion是LiveData下的變量,因為是公用一個mVersion所以,mVersion其實是一直往上加的。而mLastVersion是observer下的,通過源代碼可以發(fā)現(xiàn)。

 @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
       ...
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
      ...
    }

observer其實就是LifecycleBoundObserver。每次調(diào)用observe后都會new一個出來。所以observer.mLastVersion跳轉(zhuǎn)到第二界面的時候其實是初始化值-1.
自然就比mVersion小。

反射代碼這里就不講了。比較基礎(chǔ)。

后續(xù)

希望能夠接入RxJava可以自由切換線程,這樣能更好用

?著作權(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)容