Method of use
LiveData can be thought of as an observer pattern implementation with a lifecycle added. Let’s look at a usage example
private val data = MutableLiveData<User>()
data.observe(lifecycleOwner) {
// TODO
}
// Send data
data.value = User()
// Send data asynchronously
data.postValue(User())
Copy the code
Source code analysis
consumers
From observe, look at the Observe method in the LiveData class
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// Can only listen on the main thread
assertMainThread("observe");
If Lifecycle has been destroyed, return without listening
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// Wrap LifecycleOwner and Observer
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// Add an Observer to the HashMap
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if(existing ! =null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
// If the same Observer already exists, return it
if(existing ! =null) {
return;
}
// Add an Observer to Lifecycle
owner.getLifecycle().addObserver(wrapper);
}
Copy the code
LifecycleBoundObserver must inherit from LifecycleObserver
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive(a) {
// Key code to ensure that the Activity is active when the observer receives a value
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// Lifecycle is destroyed, indicating that the Activity is destroyed
if (currentState == DESTROYED) {
// Remove the listener
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while(prevState ! = currentState) { prevState = currentState;// Distribute values when the state changesactiveStateChanged(shouldBeActive()); currentState = mOwner.getLifecycle().getCurrentState(); }}@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver(a) {
mOwner.getLifecycle().removeObserver(this);
}
Copy the code
LifecycleEventObserver implementation
public interface LifecycleEventObserver extends LifecycleObserver {
void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
Copy the code
LifecycleBoundObserver inherits the ObserverWrapper, implements the LifecycleEventObserver interface, and stores the LifecycleOwner and Observer. One of the key lines of code is
mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED)
Copy the code
Used to ensure that the consumer always receives a value while the Activity is active.
Now what does the ObserverWrapper class do
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 (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
/ / distribution
dispatchingValue(this); }}}Copy the code
The general function is to call dispatchingValue to distribute the value when the state changes, so the consumer analysis ends there and then analyzes what is done after the LiveData value is set
producers
- synchronously
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
// Version+1
mVersion++;
mData = value;
dispatchingValue(null);
}
Copy the code
The code is very simple, it’s just a matter of setting the value, calling dispatchingValue and distributing the value, and saying dispatchingValue does what
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// Whether the value is currently being distributed, if so, returns directly
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// First distribution
if(initiator ! =null) {
considerNotify(initiator);
initiator = null;
} else {
/ / traverse the Observer
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
You can see the actual distributed values in considerNotify, and then scroll through the considerNotify method
private void considerNotify(ObserverWrapper observer) {
// Determine whether the current state can distribute values
if(! observer.mActive) {return;
}
if(! observer.shouldBeActive()) { observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
Copy the code
The code is as simple as taking the Observer out of ObserverWrapper and calling its onChanged method to distribute the value.
What about sending values asynchronously
- asynchronous
PostValue method
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if(! postTask) {return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
Copy the code
Post an mPostValueRunnable to the main thread using ArchTaskExecutor, so look at the mPostValueRunnable content
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run(a) {
Object newValue;
synchronized(mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); }};Copy the code
MPostValueRunnable fetched the value from mPendingData and then called the synchronous setValue method. At this point, the implementation principle of LiveData is basically finished, the code is relatively simple, the source code is only a file.