The principle and use of LiveData

LiveData

What is Livedata? What does it do? What can we use it for?

First, LiveData is an observable data storage class. This sentence can be seen as two parts, one is the observable class, and the other is the data storage class.

  • LiveData can be observed, but unlike regular observable classes, Livadata has the ability to perceive the life cycle. Meaning it follows the life cycle of other application components such as activity, fragment or service. LiveData with this awareness will only notify application component observers of the active lifecycle state.
  • LiveData is used to store data, which is its most direct function. When the data of LiveData changes, the observers of the application will be notified.

When the life cycle of the Observe class is in the Start or Resumed state, LiveData considers the Observe class to be in the active state. In other words, LiveData will only notify active observers, that is to say, observers in other life cycles will not receive notifications even if LiveData changes. The advantage of this is to avoid memory leaks.

Advantages of LiveData:

  1. Make sure the interface conforms to the data state
  2. no memory leaks
  3. No crashes when the Activity stops
  4. No more manual handling of lifecycles
  5. Data is always up to date
  6. Appropriate configuration changes
  7. Share resource

Use of LiveData:

  1. Create a LiveData instance to store some type of data. We usually do it in ViewModel.
public class NameViewModel extends ViewModel {
    
    
// Create a LiveData with a String
private MutableLiveData<String> currentName;

    public MutableLiveData<String> getCurrentName() {
    
    
        //有一个判空
        if (currentName == null) {
    
    
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }
// Rest of the ViewModel...
}
  1. There are two main ways we use LiveData.
    • One is to inherit the subclass MutableLIveData of LiveData. Because LiveData is an abstract class, we cannot inherit directly, so we can only inherit his subclasses.
    • One is to create an Observer object that defines an onChanged() method that controls what happens when the data stored by the LiveData object changes. Typically, you create Observer objects in interface controllers such as activities or fragments.
  2. Attach the Observer object to the LiveData object using the observe() method. The observe() method takes a LifecycleOwner object. This causes the Observer object to subscribe to the LiveData object so that it is notified of changes. Typically, you attach Observer objects to interface controllers such as activities or fragments.

Part of the source code analysis of LiveData

MutableLiveData public data update

The subclass of LiveData, MutableLiveData, is a subclass that we can use directly. There is no public method in LiveData to update the stored data, but MutableLiveData provides us with two methods to modify the value of the LiveData object: setValue(T) and postValue(T). Similarly, these two methods also rewrite the methods in LiveData. These two methods are applicable to different threads.

package androidx.lifecycle;

/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    
    

    /**
     * Creates a MutableLiveData initialized with the given {@code value}.
     *
     * @param value initial value
     */
    public MutableLiveData(T value) {
    
    
        super(value);
    }

    /**
     * Creates a MutableLiveData with no value assigned to it.
     */
    public MutableLiveData() {
    
    
        super();
    }
/**
 * 如果有活动的观察者,值将被发送给他们。
 * @param value 新值
 * 只能在主线程调用
 */
    @Override
    public void postValue(T value) {
    
    
        super.postValue(value);
    }
/**
 * 如果有活动的观察者,值将被发送给他们。
 * @param value 新值
 * 只能在子线程调用
 */
    @Override
    public void setValue(T value) {
    
    
        super.setValue(value);
    }
}

observe subscribe source code analysis

Obeserve subscription has two methods. One perceives the life cycle observe(), and one does not perceive the life cycle observeForever().

The method of registering observe needs to pass in two parameters, which are the observers who receive events from the owner of the life cycle (usually Activity, Fragment, Service).

@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);
}

Let's analyze it sentence by sentence:

  1. This method must be executed on the main thread, otherwise an exception will be thrown.
  2. The owner of the life cycle cannot be in the destroyed state, otherwise the method will end. Or ignore subscription requests
  3. The owner of the lifecycle lifecycleOwner and the observer of the event are packaged and registered as a LifecycleBoundObserver object, which is why LiveData can perceive the lifecycle.
  4. Packages and observers must correspond, and an observer cannot observe multiple life cycles at the same time. But a life cycle can bind multiple observers
  5. Adding an observer, it can be clearly seen here that the added observer is a wrapper, not the observer parameter we passed in.
@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);
}

Conclusion: The observer created by this method will always receive the callback of data changes. When the component is destroyed, the user needs to manually removeObserver().

Sentence-by-sentence analysis:

  1. Here we only pass in the observer we want to set. There is no passed in lifetime owner.

  2. Wrap the observer into an instance of AlwaysActiviteObserver. Similarly, wrapper and observer are corresponding, if it has been added to LiveData, then an exception will be thrown.

  3. The activeStateChanged() method passes true. Sets the observer to be active immediately. It will always be kept active, which is the secret of the fact that he keeps receiving data change callbacks.

observe remove source code

There are also two observe removal methods provided by LiveData, one is to remove the observer passed in by the removeObserve() method. The other is to remove the life cycle owner passed in by the removeObserve() method, which will directly remove all bound observers of the life cycle.

public void removeObserver(@NonNull final Observer<? super T> observer) {
    
    
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
    
    
        return;
    }
    removed.detachObserver();
    removed.activeStateChanged(false);
}

Source code analysis:

  1. Judge the main thread
  2. Separating Observers and Lifecycle Owners
  3. Set the observer's status to inactive all the time.
@SuppressWarnings("WeakerAccess")
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
    
    
    assertMainThread("removeObservers");
    for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
    
    
        if (entry.getValue().isAttachedTo(owner)) {
    
    
            removeObserver(entry.getKey());
        }
    }
}

A traversal is obviously performed here, and the method of removing a single Observer is called one by one.

LIfecycleBoundObserverl class and AlwaysActiveObserver class

These two classes are the wrappers we packaged above, and they both inherit from ObserWrapper.

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    
    
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
    
    
        super(observer);
        mOwner = owner;
    }
//活动态,返回true
    @Override
    boolean shouldBeActive() {
    
    
        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());
    }
//判断当前的owner是绑定的owner
    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
    
    
        return mOwner == owner;
    }
//分离观察者和生命周期拥有者
    @Override
    void detachObserver() {
    
    
        mOwner.getLifecycle().removeObserver(this);
    }
}

The methods in the LifecycleBoundObserver class are methods that inherit the ObserverWrapper abstract class or implement the GenericLifecycleObserver interface. Implementing the onStateChanged() method of GenericLifecycleObserver is why LiveData can observe the life cycle, and there is no memory leak when using LiveData. When the life cycle is in the destroyed state, Observe will be removed.

private class AlwaysActiveObserver extends ObserverWrapper {
    
    

    AlwaysActiveObserver(Observer<? super T> observer) {
    
    
        super(observer);
    }
//这里默认返回true,观察者一直收到回调
    @Override
    boolean shouldBeActive() {
    
    
        return true;
    }
}

Analysis of postValue and setValue in LiveData

These two methods are used to update data, use postValue and setValue to transfer data, and pass in data parameters in the onChange() method to update.

//子线程
protected void postValue(T value) {
    
    
    boolean postTask;
    synchronized (mDataLock) {
    
    
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
    
    
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

I didn't post all the code. ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);Obviously, this is to pass the data back to the main thread, and in the main thread, the setValue() method will be called again.

//主线程
@MainThread
protected void setValue(T value) {
    
    
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

The main thread checks, assigns, and distributes operations. The main logic is in the dispatchingValue() method.

private volatile Object mData = NOT_SET;

Here we need to mention a very important variable mData, the variable that stores data, you can see that it can accept data of Object type, and it is of volatile type. For this type of variable, the compiler will directly access it from the original memory address .

@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    
    
// mDispatchingValue的判断主要是为了解决并发调用dispatchingValue的情况
// 当对应数据的观察者在执行的过程中, 如有新的数据变更, 则不会再次通知到观察者。所以观察者内的执行不应进行耗时工作
    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);
    mDispatching

It's really complicated, but we just need to understand that it ends up calling the considerNotify() method to distribute our mData.

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;
    }
    //检查版本号
    //每次setValue,version都会加一,当它超过我们的预设版本后,直接返回,防止我们多次调用onChange方法。
    if (observer.mLastVersion >= mVersion) {
    
    
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

When the above onChange () method is quite familiar! Here the mData variable is received.

The method that will be used when customizing LiveData:

void onActive () Called when the number of active observers change to
1 from 0. This callback can be used to know that this LiveData is
being used thus should be kept up to date.

When this method is called, it means that the number of LiveData observers has changed from 0 to 1. At this time, as far as our location monitoring is concerned, we should register our time monitoring.

void onInactive () Called when the number of active observers change
from 1 to 0. This does not mean that there are no observers left,
there may still be observers but their lifecycle states aren’t STARTED
or RESUMED (like an Activity in the back stack). You can check if
there are observers via hasObservers().

When this method is called, it means that the number of LiveData observers has become 0. Since there are no observers, there is no reason to monitor. At this time, we should remove the position monitor.

Flowchart of LiveData data monitoring mechanism

img

Guess you like

Origin blog.csdn.net/qq_43867812/article/details/128054835