LiveDataBus is familiar, and there are plenty of reflection-enabled LiveDataBus on the web. But the code implemented through reflection is messy and difficult to understand. Here is a version of the code implemented. More concise and elegant ~

First, let’s look at the LiveData principle

This is how we usually use it, create a LiveData to send data and register it where you want to observe it. That way, as soon as the data is launched, you can get the data you want.

The following is the call flow when you use the red box statement again

Go to the observe method first

So we created LifecycleBoundObserver (Observe methodnew Observer) and the host (passed in the observe methodthis) to establish a connection.

So the host will call onStateChanged to LifecycleBoundObserver every time its lifecycle changes. As can be seen from the code, the host will actively remove the current mObserver when its lifecycle is DESTROYED to complete automatic unregistration. Note the distinction between mObservers and mObserver

There are a few things to note here: 1. The mObservers in LiveData is a Map and there is an mVersion field that defaults to -1

LifecycleBoundObserver inherits mObserver from ObserverWrapper, which saves itself and has an mLastVersion field, which defaults to -1

Proceed to the activeStateChanged method without much explanation of the other methods. So let’s go to dispatchingValue and you can see that dispatchingValue is notified wherever we go

Next let us considerNotify

See here I believe you already know why we can get the data onChanged

The viewModel. LiveDataObject. Observe (this, new Observer < Bean > () {@ Override public void onChanged (Bean data) {receive data}});Copy the code

So let’s look at postValue and setValue

You can see that setValue is annotated with MainThread, indicating that it can only be used in the MainThread

PostValue doesn’t, it throws an event onto the main thread

Now, if we look at what postValue does when it switches to the main thread, we see that the method in its Runnable actually does setValue after all.

So the way you look at it is postValue can only be executed on the child thread, but the message has to be sent to the main thread, and setValue is executed on the main thread only

After executing setValue or postValue, mVersion+1 is then considered

How do sticky events come about?

In order to create a stickiness event, I send the data before REGISTERING the observer, and then click the button to register another observer. We can find that even the data sent before is still accepted. This is the stickiness event.

The reason for this is mLastVersion and mVersion

Implement your own LiveDataBus

LiveData basic understanding, next to implement their own, can accept sticky events, and can accept ordinary events.

How to control sticky events

If we flag a receiveSticky variable as true to accept a sticky event, then calling a method that sends data as false will skip this method

if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; {if (receiveSticky) observer. MObserver. OnChanged (mData (T)); } else {// Handle normal events}Copy the code

Assuming we can add this field directly to the source code, where does the receiveSticky come from?

1. Sender’s perspective: Start with postValue and setValue

For example, postValue(data,receiveSticky) has a disadvantage. In this way, only sticky or non-sticky messages can be sent. If multiple hosts listen to the same message, some need stickiness and some don’t, it is difficult to control

2. From the recipient’s perspective: Start with an observer

We know that the Observer we passed in has mLastVersion only after it is wrapped as a Lifecyclebound Server. So we can look at this idea

For example: LifecycleBoundObserver wrap, with mLastVersion, we’ll pass in the receiveSticky as well as the Observer (this is not the full version, just for the record).

How do I ensure that I receive the same event

        liveData.postValue
        viewModel.liveData.observer(this , Observer {

        })
Copy the code

Generally, we send and receive in this way. Only when the LiveData is the same, can we receive the same data

So we also have to ensure that it is the same LiveData in LiveDataBus.

Same idea, to distinguish LiveData, just give LiveData a name

I’ll wrap LiveData with another layer and let the caller pass in the name to generate it

After generating, save it and use the name to find the corresponding LiveData

Like:

So this is how it’s used: the receiver is a little too complicated.

Since observer is a method in LiveData and every time a message is sent isStickyObserver(sticky, Observer())We can then duplicate the Observer in our wrapper class, for example:

So the sending and receiving data becomes a little bit better than it was before

How do I resolve the reception of ordinary events

We didn’t actually deal with ordinary events up here. We can tell whether sticky events are accepted or not by using sticky events, but we don’t know if any message events were sent before we registered

Override fun onChanged(t: t) {if (sticky) {observer.onchanged (t)} else {// Common event}}Copy the code

Remember, how do sticky events occur?

Simply assume that observer.mlastVersion (observer) < mVersion(LiveData) will generate sticky events

So we can do a little bit of a parody of that, we can do two variables

In our LiveDate

In our Observe it will be rewritten like this

So obviously you can’t completely copy the source code

The stickiness event is being sent

So when YOU initialize the StickyObserver, mLastVersion and MLiveDatSpanning don’t align,

Cause the if (mLastVersion > = stickyLiveData. MLiveDataVersion) {} not entered

So there’s a sticky event going into the if condition, so we’re going to change it to this

code

Object LiveDataBus {// LiveDatabus. with<String>("TestLiveDataBus").poststickyData ("Test!" ) // LiveDataBus.with<String>("TestLiveDataBus") .observerSticky(this, false) { // // } private val mStickyMap = ConcurrentHashMap<String, StickyLiveData<*>>() fun <T> with(eventName: String): StickyLiveData<T> { var stickyLiveData = mStickyMap[eventName] if (stickyLiveData == null) { stickyLiveData = StickyLiveData<T>(eventName) mStickyMap[eventName] = stickyLiveData } return stickyLiveData as StickyLiveData<T> } /** * */ class StickyLiveData<T>(private var eventName: String) : LiveData<T>() { var mLiveDataVersion = 0 var mStickyData: T? = null fun setStickyData(stickyData: T) { mStickyData = stickyData setValue(stickyData) } fun postStickyData(stickyData: T) { mStickyData = stickyData postValue(stickyData) } override fun setValue(value: T) { mLiveDataVersion++ super.setValue(value) } override fun postValue(value: T) { super.postValue(value) } fun observerSticky(owner: LifecycleOwner, sticky: Boolean, observer: The Observer < T > in) {/ / remove yourself save StickyLiveData owner. The lifecycle. The addObserver (LifecycleEventObserver {_, event -> if (event == Lifecycle.Event.ON_DESTROY) { mStickyMap.remove(eventName) } }) super.observe(owner, StickyObserver(this, sticky, observer)} /** * Override fun observe(owner: override fun observe(owner: override fun observe(owner: override fun observe) LifecycleOwner, observer: Observer<in T>) { observerSticky(owner,false, observer) } } class StickyObserver<T>( private val stickyLiveData: StickyLiveData<T>, private val sticky: Boolean, private val observer: Observer<in T> ) : Observer<T> {/** ** * one piece of data, TestName, * corresponds to a StickyLiveData, which corresponds to a version, and the initial value is 0, and this can be reused * and it creates a StickyObserver, Corresponding to a mLastVersion, The initial value is 0 * * if StickyLiveData#version and StickyObserver#mLastVersion are not aligned * LastVersion < version -> send the data directly, The source code is so misaligned, There is no control over stickiness events * * because the source stream wraps the incoming Observer as LifecycleBoundObserver(inherits ObserverWrapper) and saves the incoming Observer in hashMap * Finally, when considerNotify completes the hashMap, the active observer calls observer.onchanged (t) to send data * * So wrap the passed observer as StickyObserver LifecycleBoundObserver * So eventually sending data will call onChanged on StickyObserver to handle sticky events * */ private var mLastVersion = stickyLiveData.mLiveDataVersion override fun onChanged(t: T) { if (mLastVersion >= stickyLiveData.mLiveDataVersion) { if (sticky && stickyLiveData.mStickyData ! = null) { observer.onChanged(stickyLiveData.mStickyData) } return } observer.onChanged(t) } } }Copy the code