This is the sixth day of my participation in the August Text Challenge.More challenges in August
A simple introduction
LiveData is an observer-based component that is part of the Android JetPack component and is very useful for development. LiveData is a data holding class that distributes data, and because of its internal encapsulation of life cycle callbacks, the data is called back only during the appropriate life cycle, not after the listener has destroyed it, causing an exception.
Let’s use a simple example to analyze the LiveData source.
Same page pass value
We first listen in the onCreate method and change the data by clicking the button. As you can see, our callback is printed each time we change the data.
LiveDataTest.getLiveData().observe(this, {
Log.d("TAG", "MainActivity $it")
})
btnFirst.setOnClickListener {
LiveDataTest.setData("1")
}
// MainActivity 1
Copy the code
Observe the observe method first to verify that it is the main thread and return if the host is already in a DESTROYED lifecycle. The host and callback methods are then wrapped as LifecycleBoundObserver, and the callback method and wrapper are saved to mObservers. If the callback method already exists and the host is not consistent, the submission is repeated and an error is reported. If only the callback method exists, it returns directly. Otherwise, call the addObserver method to bind the Wrapper to the host lifecycle.
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>(); @MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing ! = null && ! existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing ! = null) { return; } owner.getLifecycle().addObserver(wrapper); }Copy the code
If you need to call setValue in the main thread, you can use the postValue method in the child thread. The version number is then incremented, the mData value is modified, and the dispatchingValue(NULL) method is called for the data method.
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
Copy the code
Let’s continue with the dispatchingValue method, and since our input is null, we’ll go inside the for loop and call the notice callback method.
void dispatchingValue(@Nullable ObserverWrapper initiator) { if (mDispatchingValue) { mDispatchInvalidated = true; return; } mDispatchingValue = true; do { mDispatchInvalidated = false; if (initiator ! = null) { considerNotify(initiator); initiator = null; } else { for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; }Copy the code
In the notified method, if the host is not active, it is not notified. The host state is checked again, the version number is checked, the new version number is assigned, and the onChanged method of the callback is called.
private void considerNotify(ObserverWrapper observer) { if (! observer.mActive) { return; } // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet. // // we still first check observer.active to keep it as the entrance for events. So even if // the observer moved to an active state, if we've not received that event, we better not // notify for a more predictable notification order. if (! observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); }Copy the code
Different pages pass values
Following the example above, we add a second page and change the value on the second page. This is because the first page does not receive the callback method because the state is already inactive. Then go back to the first page and you can see that the callback method for the first page is called because the state has become active.
The first case is pretty easy to answer, because the first line of the notice method is considered, and if the notice method isn’t active, the callback isn’t called. In the second case, we are not registered again, so LiveData is listening for our lifecycle. We are inside the LifecycleBoundObserver class, so we can see that we will call onStateChanged when our host state changes. This is done to our host’s life cycle, and if it’s already in a destroyed state, it’s removed. If the state changes and becomes active, the data callback method is called, which explains our second case.