This is the 22nd day of my participation in the More text Challenge. For details, see more text Challenge
Source code analysis
LiveData#observe
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
When we call observer(), we pass two arguments. The first is an instance of the LifecycleOwner interface, which our inherited AppCompatActivity parent already implements, so we pass this. The second parameter, Observer, is the callback we observe.
Owner.getlifecycle ().getCurrentState() ¶ If it is destroyed, return it (since we said that only active components will be updated).
The owner and observer are then constructed as LifecycleBoundObserver instances, an inner class that contains a series of operations related to state transitions, which will be examined in more detail later.
The observer and wrapper are then placed in the Map cache, and an exception is thrown if the observer cache already exists and is bound to another LifecycleOwner. If the cache already exists, it is ignored.
That is, an Observer instance can only be bound to one LifecycleOwner, while an owner can be bound to multiple Observer instances;
Finally, call the addObserver method to bind the LifecycleBoundObserver instance to the LifecycleOwner. And addObserver is an implementation that calls the LifecycleRegistry class.
When the owner (Activity or fragment) life cycle changes, the LifecycleBoundObserver onStateChanged method is called, The onStateChanged method in turn calls back to the Observer’s onChange method.
LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive(a) {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver(a) {
mOwner.getLifecycle().removeObserver(this); }}Copy the code
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive(a);
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver(a) {}void activeStateChanged(boolean newActive) {
// If the old and new states are the same, ignore
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
// The number of active observers ranges from 0 to 1
if (wasInactive && mActive) {
onActive();// Empty implementation, usually let subclasses override
}
// The number of active observers ranges from 1 to 0
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();// Empty implementation, usually let subclasses override
}
// Active state, which sends the LiveData value to the observer
if (mActive) {
dispatchingValue(this); }}}Copy the code
Take a look at LifecycleBoundObserver, which inherits ObserverWrapper and implements the GenericLifecycleObserver interface. The GenericLifecycleObserver interface implements the LifecycleObserver interface. It wraps our external observer, somewhat similar to the proxy pattern. We can review the Lifecycle component. The onStateChanged() method is used to call back when the lifecycle of a component (Fragment, Activity) changes.
GenericLifecycleObserver#onStateChanged
When the Activity callback cycle changes, it will call back onStateChanged, first checking whether mowner.getLifecycle ().getCurrentState() has destroyed, if. Has destroyed, directly remove the observer. This is why we do not need to manually remove the observer.
If the state is not destroyed, the activeStateChanged method is called with the value returned by shouldBeActive(). When lifecycle’s state is STARTED or RESUMED, the shouldBeActive method returns true, indicating activation.
In the activeStateChanged method, when newActive is true and not equal to the last value, the LiveData mActiveCount count will be increased. As you can see, onActive fires when mActiveCount is 1, and onInactive only fires when mActiveCount is 0. That is, when the onActive method is called, the active observer is exactly 1. When the onInactive method is called, none of the observers are active.
When mActive is true, the dispatchingValue method is activated.
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// If it is being processed, return directly
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// If the initiator is not null, call the notice method
if(initiator ! =null) {
considerNotify(initiator);
initiator = null;
} else { // When null, all obsever are traversed and distribution is made
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break; }}}}while (mDispatchInvalidated);
// Set to false when distribution is complete
mDispatchingValue = false;
}
Copy the code
MDispatchingValue and mDispatchInvalidated can only be used in the dispatchingValue method. Obviously, these two variables are used to prevent duplicate distribution of the same content. When the initiator is not null, only the current observer is processed. When the initiator is null, all obsever are traversed and distributed
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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
Copy the code
- If the state is not active, return it directly. This is why we do not call back the onChange method of the observer when our Activity is in onPause, onStop, or onDestroy.
- Determines whether the data is up to date. If it is, return without processing
- The data is not up to date, call back to the mobServer.onchanged method. And pass the mData
LiveData#setValue
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
Copy the code
In the setValue method, first, the assertion is the main thread, followed by mVersion + 1; The value is assigned to mData and then the dispatchingValue method is called. DispatchingValue is passed null to indicate that all observers are processed.
If the activity we are attached to is in onPause or onStop, we will not call the onChange method of the observer, although the dispatchingValue method is returned directly. But when the attached activity comes back to the foreground, it triggers the LifecycleBoundObserver onStateChange method, which in turn calls the dispatchingValue method. In this method, Because mLastVersion < mVersion. So the onChange method of obsever is called back, and this is where LiveData is clever
Similarly, if you call the setValue method of LiveData multiple times while the activity is in the background, you will only end up calling back the onChange method of the LiveData Observer once.
LiveData#postValue
protected void postValue(T value) {
boolean postTask;
/ / lock
synchronized (mDataLock) {
// No one is currently working on the POST task
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if(! postTask) {return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run(a) {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
// Set mPendingData to NOT_SET after processing
mPendingData = NOT_SET;
}
//noinspection uncheckedsetValue((T) newValue); }};Copy the code
- First, use the synchronization mechanism, postTask = mPendingData == NOT_SET whether someone is working on the task. True, no one is working on the task, false, someone is working on the task, if someone is working on the task, just return
- Call AppToolkitTaskExecutor. GetInstance (). The postToMainThread to the main thread mPostValueRunnable missions.
LiveData#observeForever
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if(existing ! =null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if(existing ! =null) {
return;
}
wrapper.activeStateChanged(true);
}
Copy the code
Because AlwaysActiveObserver does not implement the GenericLifecycleObserver method interface, the onStateChange method is not called back when the Activity O lifecycle changes. The observer will not be removed voluntarily. Because our obsever is removed depends on calling back to the onStateChange method of the GenericLifecycleObserver when the Activity lifecycle changes.
Sequence diagram
Borrow a picture from the Internet
There are three main timings involved in LiveData:
- Add the observer(second parameter in the observer() method) to the Fragment/Activity via liveData.observer ().
- Remove observers or notify observers to update data as the Fragment/Activity lifecycle changes.
- When the setValue() and postValue() methods of LiveData are called, the observer is notified to update the data.
todo
NetworkBoundResource
Juejin. Cn/post / 684490…
permissions
Juejin. Cn/post / 5 c106a…
conclusion
LiveData advantages
1. Ensure that the UI conforms to the data state. LiveData notifies the Observer when the lifecycle state changes. You can incorporate code that updates the UI into these Observer objects. Instead of considering the timing of the data changes, the Observer updates the UI every time the data changes.
2. No memory leak Observer will bind objects with a lifetime and clean up after the bound object is destroyed.
If the Observer life cycle is inactive, such as an Activity on the back stack, it will not be notified of any LiveData events.
There is no need to manually process the life cycle. UI components only need to observe the relevant data. There is no need to manually stop or resume the observation. LiveData manages these things automatically because, as it observes, it is aware of the lifecycle changes of the corresponding components.
5. Keep Data Up to date If an object becomes inactive in its lifetime, it will receive the latest data when it becomes active again. For example, a background Activity receives the latest data immediately after returning to the foreground.
6. Respond to Configuration Changes Properly If an Activity or Fragment is recreated as a result of a configuration change, such as device rotation, it immediately receives the latest available data.
7. Sharing resources you can use the singleton pattern to extend LiveData objects and wrap them as system services for sharing across applications. Once a LiveData object is connected to a system service, any Observer that needs the resource simply observes the LiveData object.
Use the LiveData object step
LiveData
Based on the observer pattern implementation, and andLifecycleOwner
To bind, andLifecycleOwner
Has beenFragment
And the Activity implementation, so it can sense the lifecycle; LifecycleOwner is not active at the current time (for exampleonPasue()
,onStop()
), LiveData does not call backobserve()
Because it doesn’t make sense.- At the same time
LiveData
Only inLifecycleOwner
In aActive
If the data change occurs in the inactive state, the data will change, but no notification is sent, etcowner
Return to the active state and send the notification. LiveData
Will be removed in DESTROYEDObserver
, unsubscribe without memory leakspostValue
In an asynchronous thread,setValue
In the main thread- if
LiveData
Has not beenobserve()
Then you call the postValue(…) of this LiveData /value=… , it isIt doesn’t make any difference
reference
Official documentation :LiveData Overview
Jetpack source code parsing – Use and how LiveData works
Android LiveData source code anatomy
Android source code parsing -LiveData