summary
In the last article, we introduced the basic use and principle analysis of ViewModel. Because ViewModel usually needs to be used in combination with inter component communication tools, the last article also talked about the scenario of the combination of ViewModel and LiveData. This time, we will analyze some principles of LiveData combined with the examples in the previous article.
1. Use
Because this time we will mainly analyze some principles of LiveData, we will not create a Demo. To facilitate analysis, paste the last part of the code:
// Note 1, registered observer mLiveData.observe(this, new Observer<String>() { @Override public void onChanged(String s) { Toast.makeText(getApplicationContext(), "mag = " + s, Toast.LENGTH_SHORT).show(); } }); // Note 2, transmit data mLiveData.postValue(result);
2. Source code analysis
Now let's start with notes 1 and 2 above to analyze the registration and data transmission process of LiveData.
- To register, first look at the registration process of the observer. The observe method in note 1 above:
// LiveData.java public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); if (owner.getLifecycle().getCurrentState() == DESTROYED) { // Note 3, get the Activity life cycle // If the component is in the DESTROYED state, registration is not allowed return; } LiveData.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer); // Note 4: package the component and observer and store them in the linked list. If the object already exists, it will not be overwritten and existing will not be empty LiveData.ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } // Note 5: if the observer already exists, return and do not repeat the registration if (existing != null) { return; } // Note 6, save the observer in Lifecycle to complete the registration owner.getLifecycle().addObserver(wrapper); } //Note 7, putIfAbsent method public V putIfAbsent(@NonNull K key, @NonNull V v) { SafeIterableMap.Entry<K, V> entry = get(key); if (entry != null) { return entry.mValue; } put(key, v); return null; }
In note 3 above, we can see that LiveData judges the state of the observer component life cycle before registering the observer. If the observer lifecycle is already in If the status is DESTROYED, it will be returned directly and will not be registered. Then, at the place of note 4, the wrapped observer object will be saved into the Map in the form of key value pairs.
If the object already exists, the overwrite operation is not performed, and the existing returned is not null. At this time, the registration method returns directly, and the registration will not be repeated. See note 7 for putIfAbsent storage method logic.
If the packaged observer object has not been saved and registered before, complete the registration in the Lifecycle of note 6 above. Now look at the observer wrapper class LifecycleBoundObserver in LiveData at note 4 above:
// LiveData.java class LifecycleBoundObserver extends LiveData.ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { // Note 8, when the component life cycle changes, the method is called back // When the component lifecycle state is DESTROYED, the observer is removed // In this way, no data will be received when the observer component is in the destroyed state removeObserver(mObserver); return; } activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); } } // Remove observer public void removeObserver(@NonNull final Observer<? super T> observer) { assertMainThread("removeObserver"); LiveData.ObserverWrapper removed = mObservers.remove(observer); if (removed == null) { return; } removed.detachObserver(); removed.activeStateChanged(false); }
The onStateChanged method in note 8 above calls back when the component life cycle changes. After judgment, the observer will be removed when the component lifecycle state is DESTROYED. In this way, no data will be received when the observer component is in the DESTROYED state.
According to the above analysis of the registration process, we briefly summarize the following two points for the LiveData life cycle:
(1) LiveData is not registered when the observer is destroyed
(2) LiveData has the life cycle awareness of components (through LifeCycle). When the component is destroyed, LiveData removes the observer to avoid memory leakage.
- Next, go back to note 2 above and start with the LiveData.postValue(result) method to see the LiveData data data sending process:
// LiveData.java public void postValue(T value) { super.postValue(value); } protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) { return; } // Note 9: package the message to be sent and switch to the main thread to execute the setValue () method ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); } private final Runnable mPostValueRunnable = new Runnable() { @SuppressWarnings("unchecked") @Override public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } // Note 10, the setValue () method is executed in the main thread setValue((T) newValue); } };
From the comments above, we can see that the postValue method finally switches to the main thread and executes the setValue method. Now let's look at the setValue method:
// LiveData.java protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); } void dispatchingValue(@Nullable LiveData.ObserverWrapper initiator) { ...... for (Iterator<Map.Entry<Observer<? super T>, LiveData.ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { //Note 11, traversing the observer considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } ...... } private void considerNotify(LiveData.ObserverWrapper observer) { // Note 12: the observer life cycle is not Active and is not sent // The Active state includes STARTED and RESUMED, that is, onStart() and onResume() methods corresponding to our component life cycle if (!observer.mActive) { return; } ...... observer.mObserver.onChanged((T) mData); }
As we can see above, setValue will call the dispatchingValue(null) method to distribute events.
The dispatchingValue method will traverse all observers and then execute the considerNotify method. So will LiveData send data to all observers? See note 12 above. Before sending data, LiveData will judge the current life cycle state of the observer.
Only observers who are currently active will receive data, and Active States include STARTED and RESUMED, that is, onStart() and onResume() methods corresponding to our component life cycle.
This is the conclusion we need to know. The data of LiveData will be received only when the component lifecycle is in the Start or Resume state. In this way, the component does not need to judge its current state when receiving data display.