This article has been authorized to be reprinted by guolin_blog, an official wechat account.

This article is mainly for LiveData source analysis, it is recommended to read the article against the sample code, the sample code is as follows:

LiveDataDemo

This article uses the source code analysis of Android SDK 29.

define

LiveData is an observable data store class with lifecycle awareness that follows application components (e.g. The lifecycle of activities, fragments, and Services (you can use LifecycleService, which implements the LifecycleOwner interface). This awareness ensures that LiveData updates only application component observers that are in an active lifecycle state.

If an Observer (represented by an Observer class) is in a STARTED or RESUMED state during its lifecycle, LiveData will assume that the Observer is active and will notify it of updates, while inactive observers registered observing a LiveData object will not receive notification of changes.

Application components all implement the LifecycleOwner interface and with this relationship Lifecycle objects are removed when the state of the corresponding Lifecycle object changes to DESTROYED.

Advantages of using LiveData:

  • Ensure that the interface conforms to the data state

    LiveData follows the Observer pattern, notifying observers when the lifecycle state changes and then updating the interface.

  • No memory leaks will occur

    When the application component’s lifecycle is in a DESTROYED state, the observer is removed so that it no longer holds references to the application component.

  • It does not crash when the Activity stops

    If the observer’s life cycle is inactive (for example, return Actvity in the stack), it will not accept any LiveData events.

  • You no longer need to handle the life cycle manually

    The interface component simply observes the relevant data and does not stop or resume the observation, and LiveData automatically manages all of these operations because it senses the relevant lifecycle state changes as it observes.

  • Data is always up to date

    If the life cycle becomes inactive, it will receive the latest data when it becomes active again. For example, an Activity that was in the background will receive the latest data as soon as it returns to the foreground.

  • Appropriate configuration changes

    If an Activity or Fragment is recreated due to a configuration change (for example, device rotation), it will immediately receive the latest data.

  • Shared resources

    We can use the singleton pattern to inherit LiveData to encapsulate related business logic so that it can be shared across applications.

Using LiveData

The steps are as follows:

  1. Typically, a LiveData instance is created in a ViewModel to store some type of data.
  2. Create an Observer object and implement its onChanged method, which controls what to process when the data stored by the LiveData object changes.
  3. In most cases, the LiveData object is observed in the onCreate method of the application component, and the Observer method of the LiveData object is called with two parameters. The first parameter is LifecycleOwner, which is an interface, The Activity, Fragment, and LifecycleService all implement this interface, and the second parameter is the Observer created in step 2, so that the Observer can subscribe to the LiveData object to be notified of changes.

Note: Make sure that the LiveData object used to update the interface is stored in a ViewModel object, not in an Activity or Fragment, for the following reasons:

  1. Avoid activities or fragments that are too large because these interface controllers are only responsible for displaying data, not storing data state.
  2. Separating the LiveData instance from activities and fragments allows it to continue to exist after configuration changes.

The sample code

Add the following dependencies to the project:

implementation 'androidx. Lifecycle: lifecycle - extensions: 2.2.0 - alpha02'
implementation 'org. Jetbrains. Kotlinx: kotlinx coroutines -- core: 1.3.0'
implementation 'org. Jetbrains. Kotlinx: kotlinx coroutines - android: 1.3.0'
implementation 'androidx. Lifecycle: lifecycle - viewmodel - KTX: 2.2.0 - rc03'
Copy the code

Since I’m using DataBinding, I add the following code:

dataBinding {
    enabled = true
}
Copy the code

The project structure is as follows:

Define MainViewModel and inherit from ViewModel, create two MutableLiveData in this class, firstContent is to demonstrate updating the LiveData object in the main thread, SecondContent is used to demonstrate updating a LiveData object on a worker thread as follows:

/** * Created by TanJiaJun on 2019-12-22. */
class MainViewModel : ViewModel() {

    private val _firstContent = MutableLiveData<String>().apply {
        value = "The first text"
    }
    val firstContent: LiveData<String> = _firstContent

    private val _secondContent = MutableLiveData<String>().apply {
        value = "The second text"
    }
    val secondContent: LiveData<String> = _secondContent

    // Update the LiveData object in the main thread, calling the setValue method of MutableLiveData, which will be analyzed below
    fun changeFirstContent(text: String) {
        _firstContent.value = text
    }

    // Update the LiveData object in the worker thread, calling the postValue method of MutableLiveData, which will be analyzed below
    fun changeSecondContent(text: String) =
        viewModelScope.launch {
            withContext(Dispatchers.Default) {
                _secondContent.postValue(text)
            }
        }

}
Copy the code

Define FirstFragment as follows:

/** * Created by TanJiaJun on 2019-12-22. */
class FirstFragment : Fragment(), FirstHandlers {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup? , savedInstanceState:Bundle?).: View? =
        DataBindingUtil.inflate<FragmentFirstBinding>(
            inflater,
            R.layout.fragment_first,
            container,
            false
        )
            .also { binding ->
                // The setLifecycleOwner method is called, as discussed below
                binding.lifecycleOwner = this
                // Bind the MainViewModel to the viewbinding.viewModel = activity? .let { ViewModelProviders.of(it)[MainViewModel::class.java]
                }
                binding.handlers = this
            }
            .root

    // Click Button to navigate to SecondFragment
    override fun onNavigateToSecondFragmentClick(view: View) {
        (activity as MainActivity).addFragment(SecondFragment(), FRAGMENT_TAG_SECOND)
    }

}

interface FirstHandlers {

    fun onNavigateToSecondFragmentClick(view: View)

}
Copy the code

Define SecondFragment as follows:

/** * Created by TanJiaJun on 2019-12-22. */
class SecondFragment : Fragment(), SecondHandlers {

    private var viewModel: MainViewModel? = null

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState) viewModel = activity? .let { ViewModelProviders.of(it)[MainViewModel::class.java]}
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup? , savedInstanceState:Bundle?).: View? =
        DataBindingUtil.inflate<FragmentSecondBinding>(
            inflater,
            R.layout.fragment_second,
            container,
            false
        )
            .also {
                it.handlers = this
            }
            .root

    // Click on the first Button to call the changeFirstContent method in MainViewModel. Change the text of the first TextView in the FirstFragment from "the first text" to "the first text changed".
    override fun onChangeFirstContentClick(view: View){ viewModel? .changeFirstContent(getString(R.string.first_content_changed)) }// Click on the second Button to call the changeSecondContent method in MainViewModel. Change the text of the second TextView in the FirstFragment from "second text" to "second text changed".
    override fun onChangeSecondContentClick(view: View){ viewModel? .changeSecondContent(getString(R.string.second_content_changed)) } }interface SecondHandlers {

    fun onChangeFirstContentClick(view: View)

    fun onChangeSecondContentClick(view: View)

}
Copy the code

Since I’m also using DataBinding, ViewModel, and Kotlin coroutines, I’ll start with the source code as written in the official documentation below.

Source code analysis

LiveData is an abstract class. We mainly use MutableLiveData and MediatorLiveData as two subclasses. Let’s first look at the structure diagram of LiveData:

Let’s take a look at a few common methods, starting with the Observer method, which is used to add specified observers to the watch list in the specified LifecycleOwner, as follows:

// LiveData.java
// Create a Map with key Observer and value ObserverWrapper
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    // Check if it is on the main thread. If it is not, an exception will be thrown
    assertMainThread("observe");
    // Check whether LifecycleOwner is in the DESTROYED state
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // If yes, return
        return;
    }
    // Create LifecycleBoundObserver and wrap the LifecycleOwner and Observer passed in. This class will be examined below
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // Store LifecycleBoundObserver in SafeIterableMap with key as Observer and value as ObserverWrapper, and return null if the Observer is stored for the first time
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    // The first condition is to determine whether the Observer is stored for the first time, and the second condition is to determine whether the Observer is already attached to the LifecycleOwner
    if(existing ! =null && !existing.isAttachedTo(owner)) {
        // If the Observer is not stored for the first time and is already attached to LifecycleOwner, throws "cannot add an attachment to a different lifecycle, but is the same Observer
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    // Again determine whether to store the Observer for the first time
    if(existing ! =null) {
        // Return if the Observer is not stored for the first time
        return;
    }
    Lifecycle calls the addObserver method
    owner.getLifecycle().addObserver(wrapper);
}
Copy the code

SafeIterableMap is a Map, which is actually a LinkedList and can be modified during iterations, but is not thread-safe, and LiveData uses it to store LifecycleBoundObserver.

Lifecycle is an abstract class whose only subclass is LifecycleRegistry. Lifecycle is an abstract class whose only subclass is LifecycleRegistry.

// LifecycleRegistry.java
// Create a FastSafeIterableMap with key as LifecycleObserver and value as ObserverWithState
private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();

// Providers that own this Lifecycle only keep weak references in LifecycleOwner, so if someone leaks a Lifecycle object, they won't leak the entire Activity or Fragment, but doing so will also leak all Listener objects, Because strong references are maintained on all Listener objects
private final WeakReference<LifecycleOwner> mLifecycleOwner;

public LifecycleRegistry(@NonNull LifecycleOwner provider) {
    mLifecycleOwner = new WeakReference<>(provider);
    mState = INITIALIZED;
}

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    // Wrap LifecycleObserver (we passed LifecycleBoundObserver) and State as ObserverWithState
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    // Store ObserverWithState in FastSafeIterableMap, key is LifecycleBoundObserver, value is ObserverWithState, If you store this object with State for the first time, null is returned
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    // Determine whether to store the ObserverWithState for the first time
    if(previous ! =null) {
        // Return if it is not the first time the ObserverWithState is stored
        return;
    }
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    // Check whether LifecycleOwner is null
    if (lifecycleOwner == null) {
        // If it is null, it should be destroyed immediately
        return;
    }

    booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        pushParentState(statefulObserver.mState);
        statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
        popParentState();
        // mState or subling may be recalculated
        targetState = calculateTargetState(observer);
    }

    // Check whether it is at the top of the stack
    if(! isReentrance) {// Perform synchronization if it is at the top of the stack
        sync();
    }
    mAddingObserverCounter--;
}
Copy the code

If it is at the top of the stack, the sync method is called, so it will not be called on reentrant. Let’s look at this method, which looks like this:

// LifecycleRegistry.java
private void sync(a) {
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    // Check whether LifecycleOwner is null
    if (lifecycleOwner == null) {
        // If null, throw an exception proving that the LifecycleRegistry LifecycleOwner has been garbage collected and it is too late to change the lifecycle
        throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                + "garbage collected. It is too late to change lifecycle state.");
    }
    while(! isSynced()) { mNewEventOccurred =false;
        ; // No need to check whether John is null because isSynced already determines
        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
            // If the state of ObserverWithState is less than the current state, the state changes in reverse order and the observer is notified
            backwardPass(lifecycleOwner);
        }
        Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
        if(! mNewEventOccurred && newest ! =null
                && mState.compareTo(newest.getValue().mState) > 0) {
            // If the state of ObserverWithState is greater than the current state, the state is changed in order and the observer is notified
            forwardPass(lifecycleOwner);
        }
    }
    mNewEventOccurred = false;
}
Copy the code

Let’s look at the forwardPass and backwardPass methods. The code looks like this:

// LifecycleRegistry.java
// Positive traversal changes the state and notifies the observer
private void forwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    // Traversal the mObserverMap in positive order
    while(ascendingIterator.hasNext() && ! mNewEventOccurred) { Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next(); ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            pushParentState(observer.mState);
            // Call the dispatchEvent method with ObserverWithStateobserver.dispatchEvent(lifecycleOwner, upEvent(observer.mState)); popParentState(); }}}// Iterate backwards to change the state while notifying the observer
private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    // Iterate backwards through the mObserverMap
    while(descendingIterator.hasNext() && ! mNewEventOccurred) { Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next(); ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            Event event = downEvent(observer.mState);
            pushParentState(getStateAfter(event));
            // Call the dispatchEvent method with ObserverWithStateobserver.dispatchEvent(lifecycleOwner, event); popParentState(); }}}Copy the code

ObserverWithState is a static inner class for LifecycleRegistry. Let’s look at the dispatchEvent method for ObserverWithState, which looks like this:

// LifecycleRegistry.java
static class ObserverWithState {
    State mState;
    LifecycleEventObserver mLifecycleObserver;

    ObserverWithState(LifecycleObserver observer, State initialState) {
        / / mLifecycleObserver LifecycleBoundObserver
        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
        mState = initialState;
    }

    void dispatchEvent(LifecycleOwner owner, Event event) {
        State newState = getStateAfter(event);
        mState = min(mState, newState);
        // Call onStateChanged method of LifecycleBoundObservermLifecycleObserver.onStateChanged(owner, event); mState = newState; }}Copy the code

LifecycleBoundObserver is an internal class of LiveData, so let’s look at onStateChanged.

// LiveData.java
// Lifecycle determines whether Lifecycle is greater than or equal to the value of the STARTED state and thus whether Lifecycle is active
@Override
boolean shouldBeActive(a) {
    return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
    Lifecycle is in a DESTROYED state
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        Lifecycle is DESTROYED, and return. The removeObserver method will be analyzed below
        removeObserver(mObserver);
        return;
    }
    // If Lifecycle is not in a DESTROYED state, call activeStateChanged and pass in the Boolean value derived from shouldBeActive
    activeStateChanged(shouldBeActive());
}
Copy the code

State is an enumeration, which looks like this:

@SuppressWarnings("WeakerAccess")
public enum State {

    DESTROYED,

    INITIALIZED,

    CREATED,

    STARTED,

    RESUMED;

    // Determine whether the current state value is greater than or equal to the value of the passed state
    public boolean isAtLeast(@NonNull State state) {
        return compareTo(state) >= 0; }}Copy the code

So we can see that the only values that are greater than or equal to STARTED are STARTED and RESUMED, so this method is to determine whether or not we’re active.

The activeStateChanged method code looks like this:

// LiveData.java
void activeStateChanged(boolean newActive) {
    // Determine whether the state has changed
    if (newActive == mActive) {
        // Return if there is no change
        return;
    }
    // If something changes, set the status immediately so that no content is sent to inactive observers
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    // If the current state is active, it increases by 1, otherwise it decreases by 1
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) {
        // If mActiveCount changes from 0 to 1 and the current state is active, onActive is called
        onActive();
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) {
        // If mActiveCount changes from 1 to 0 and the current state is inactive, onInactive is called
        onInactive();
    }
    if (mActive) {
        // If the current state is active, call dispatchingValue and pass in LifecycleBoundObserver
        dispatchingValue(this); }}Copy the code

Let’s look at the dispatchingValue method as follows:

// LiveData.java
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // Determine whether distribution is in progress
    if (mDispatchingValue) {
        // If distribution is taking place, set mDispatch validated to true and return
        mDispatchInvalidated = true;
        return;
    }
    // It is being distributed
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        // Check whether the initiator is null. According to the above code, it is not null. Pay attention to the null logic, which is involved in setValue, postValue, and getValue
        if(initiator ! =null) {
            If the initiator is not null, the Duties method is called and LifecycleBoundObserver is passed in
            considerNotify(initiator);
            initiator = null;
        } else {
            // If initiator is null, mObservers will be traversed
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                // call the notice method
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break; }}}}while (mDispatchInvalidated);
    // Distribution completed
    mDispatchingValue = false;
}
Copy the code

The two variables mDispatchingValue and mDispatchInvalidated are used to prevent repeated distribution of the same content.

Notice method code is as follows:

// LiveData.java
@SuppressWarnings("unchecked")
private void considerNotify(ObserverWrapper observer) {
    // Check whether it is active
    if(! observer.mActive) {// Return if it is not active
        return;
    }
    // Check whether the latest state is active before distribution, in case the state has changed, but we have not received the event
    if(! observer.shouldBeActive()) {// Notifications will not be distributed if they are not active
        observer.activeStateChanged(false);
        return;
    }
    // Check whether it is the latest data
    if (observer.mLastVersion >= mVersion) {
        // If the data is up to date, it will not be distributed
        return;
    }
    // Set the version to the latest version
    observer.mLastVersion = mVersion;
    // Call the onChanged method
    observer.mObserver.onChanged((T) mData);
}
Copy the code

The onChanged method has the following code:

// Observer.java
public interface Observer<T> {
    void onChanged(T t);
}
Copy the code

The onChanged method is the one we need to implement in order to implement the logic to be executed when the data changes.

Do you remember sync? If you forgot, look up again, the sync method is also called by the moveToState method, as follows:

// LifecycleRegistry.java
private void moveToState(State next) {
    if (mState == next) {
        return;
    }
    mState = next;
    // Determine whether an observer is being added or synchronized
    if(mHandlingEvent || mAddingObserverCounter ! =0) {
        mNewEventOccurred = true;
        // we will figure out what to do on upper level.
        // Return if synchronizing or adding observers
        return;
    }
    mHandlingEvent = true;
    // Call sync
    sync();
    mHandlingEvent = false;
}
Copy the code

The moveToState method is also called by the handleLifecycleEvent method, which changes the lifecycle state and notifies the observer that calling this method has no effect if the current lifecycle state is the same as the last time the method was called:

// LifecycleRegistry.java
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    State next = getStateAfter(event);
    moveToState(next);
}
Copy the code

So when is the LifecycleRegistry object created? What does it do? In our example code, MainActivity inherits AppCompatActivity, which inherits FragmentActivity, Androidx.activity.Com ponentActivity FragmentActivity inheritance, we look at the androidx.activity.Com ponentActivity code:

// androidx.activity.ComponentActivity.java
// Create a LifecycleRegistry object
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedStateRegistryController.performRestore(savedInstanceState);
    / / injection ReportFragment
    ReportFragment.injectIfNeededIn(this);
    if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}Copy the code

Let’s look at the ReportFragment code as follows:

// ReportFragment.java
private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle"
        + ".LifecycleDispatcher.report_fragment_tag";

public static void injectIfNeededIn(Activity activity) {
    ProcessLifecycleOwner should always work correctly. Some activities may not inherit FragmentActivity from Support Lib, so use FragmentActivity from the Framework
    android.app.FragmentManager manager = activity.getFragmentManager();
    if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
        manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
        // Hopefully, we are the first to make a transaction.manager.executePendingTransactions(); }}@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    dispatchCreate(mProcessListener);
    // The dispatch method is called, passing in Lifecycle.event.on_create
    dispatch(Lifecycle.Event.ON_CREATE);
}

@Override
public void onStart(a) {
    super.onStart();
    dispatchStart(mProcessListener);
    // Call the dispatch method, passing in Lifecycle.Event.ON_START
    dispatch(Lifecycle.Event.ON_START);
}

@Override
public void onResume(a) {
    super.onResume();
    dispatchResume(mProcessListener);
    // Call the dispatch method, passing in Lifecycle.Event.ON_RESUME
    dispatch(Lifecycle.Event.ON_RESUME);
}

@Override
public void onPause(a) {
    super.onPause();
    // Call the dispatch method, passing in Lifecycle.Event.ON_PAUSE
    dispatch(Lifecycle.Event.ON_PAUSE);
}

@Override
public void onStop(a) {
    super.onStop();
    // Call the dispatch method, passing in Lifecycle.Event.ON_STOP
    dispatch(Lifecycle.Event.ON_STOP);
}

@Override
public void onDestroy(a) {
    super.onDestroy();
    // Call the dispatch method, passing in Lifecycle.Event.ON_DESTROY
    dispatch(Lifecycle.Event.ON_DESTROY);
    // Ensure that references to an Activity are not disclosed
    mProcessListener = null;
}

private void dispatch(Lifecycle.Event event) {
    Activity activity = getActivity();
    // Check whether the Activity implements the LifecycleRegistryOwner interface
    if (activity instanceof LifecycleRegistryOwner) {
        // Call the handleLifecycleEvent method
        ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
        return;
    }

    // Check whether the Activity implements the LifecycleOwner interface
    if (activity instanceof LifecycleOwner) {
        Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
        Lifecycle is a subclass of LifecycleRegistry
        if (lifecycle instanceof LifecycleRegistry) {
            // Call the handleLifecycleEvent method((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); }}}Copy the code

LifecycleRegistry’s handleLifecycleEvent method is called whenever the Activity’s lifecycle changes. The moveToState method is called and the sync method is called to make LiveData aware of the Lifecycle of the Activity. This is another important component of Android Jetpack that Lifecycle works. Let’s also look at the Fragment code:

// Fragment.java
LifecycleRegistry mLifecycleRegistry;

@Nullable FragmentViewLifecycleOwner mViewLifecycleOwner;
MutableLiveData<LifecycleOwner> mViewLifecycleOwnerLiveData = new MutableLiveData<>();

private void initLifecycle(a) {
    // Create a LifecycleRegistry object
    mLifecycleRegistry = new LifecycleRegistry(this);
    mSavedStateRegistryController = SavedStateRegistryController.create(this);
    // Check whether the current Android version is larger than 4.4
    if (Build.VERSION.SDK_INT >= 19) {
        mLifecycleRegistry.addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                // Check whether the current event is ON_STOP
                if (event == Lifecycle.Event.ON_STOP) {
                    // Check whether the View is null
                    if(mView ! =null) {
                        If not empty, cancel any delayed high-level input events previously published to the event queuemView.cancelPendingInputEvents(); }}}}); }}void performCreate(Bundle savedInstanceState) {
    // Omit some code
    // Call handleLifecycleEvent, passing in Lifecycle.Event.ON_CREATE
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}

void performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    mChildFragmentManager.noteStateNotSaved();
    mPerformedCreateView = true;
    // Create the Fragment View LifecycleOwner
    mViewLifecycleOwner = new FragmentViewLifecycleOwner();
    mView = onCreateView(inflater, container, savedInstanceState);
    // Check whether the View is null
    if(mView ! =null) {
        // Create the View Lifecycle of the Fragment
        mViewLifecycleOwner.initialize();
        // Then notify some observers of the new LifecycleOwner
        mViewLifecycleOwnerLiveData.setValue(mViewLifecycleOwner);
    } else {
        / / determine whether FragmentViewLifecycleOwner initialization
        if (mViewLifecycleOwner.isInitialized()) {
            / / if the View is null, and FragmentViewLifecycleOwner initialization, throw an exception
            throw new IllegalStateException("Called getViewLifecycleOwner() but "
                    + "onCreateView() returned null");
        }
        mViewLifecycleOwner = null; }}void performStart(a) {
    // Omit some code
    // Call onStart
    onStart();
    // Omit some code
    LifecycleRegistry calls the handleLifecycleEvent method, passing in Lifecycle.event.ON_START
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
    // Check whether the View is null
    if(mView ! =null) {
        / / if the View is not null, call FragmentViewLifecycleOwner handleLifecycleEvent, incoming Lifecycle. Event. ON_START
        mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START);
    }
    // Omit some code
}

void performResume(a) {
    // Omit some code
    // Call onResume
    onResume();
    // Omit some code
    LifecycleRegistry calls the handleLifecycleEvent method, passing in Lifecycle.Event.ON_RESUME
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
    // Check whether the View is null
    if(mView ! =null) {
        / / if the View is not null, call FragmentViewLifecycleOwner handleLifecycleEvent, incoming Lifecycle. Event. ON_RESUME
        mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
    }
    // Omit some code
}

void performPause(a) {
    // Omit some code
    // Check whether the View is null
    if(mView ! =null) {
        / / if the View is not null, call FragmentViewLifecycleOwner handleLifecycleEvent method, was introduced into Lifecycle. Event. ON_PAUSE
        mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
    }
    LifecycleRegistry calls the handleLifecycleEvent method, passing in Lifecycle.Event.ON_PAUSE
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
    // Omit some code
    // Call onPause
    onPause();
    // Omit some code
}

void performStop(a) {
    // Omit some code
    // Check whether the View is null
    if(mView ! =null) {
        / / if the View is not null, call FragmentViewLifecycleOwner handleLifecycleEvent method, was introduced into Lifecycle. Event. ON_STOP
        mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    }
    LifecycleRegistry calls the handleLifecycleEvent method, passing in Lifecycle.event.ON_STOP
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    // Omit some code
    // Call onStop
    onStop();
    // Omit some code
}

void performDestroyView(a) {
    // Check whether the View is null
    if(mView ! =null) {
        / / if the View is not null, call FragmentViewLifecycleOwner handleLifecycleEvent method, was introduced into Lifecycle. Event. ON_DESTROY
        mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    }
    // Omit some code
    onDestroyView();
    // Omit some code
}

void performDestroy(a) {
    // Omit some code
    LifecycleRegistry calls the handleLifecycleEvent method, passing in Lifecycle.event.ON_DESTROY
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    // Omit some code
    // Call onDestroy
    onDestroy();
    // Omit some code
}
Copy the code

FragmentViewLifecycleOwner represents the fragments of the View of the life cycle, in most cases, this reflects the life cycle of the fragments itself, but the fragments of life cycle will certainly longer than its View of the life cycle.

Similarly, whenever the Fragment’s life cycle changes, Is called LifecycleRegistry handleLifecycleEvent method and FragmentViewLifecycleOwner handleLifecycleEvent method, and then will call moveToState method, Finally, the sync method is called to make LiveData aware of the Fragment’s life cycle.

Then we look at the removeObserver method, which looks like this:

// LiveData.java
// This method is called on the main thread
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    // Check whether it is in the main thread
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
        // Return if null
        return;
    }
    // Call the detachObserver method of LifecycleBoundObserver
    removed.detachObserver();
    // Call LifecycleBoundObserver's activeStateChanged method, passing false, which is also analyzed above and won't be covered here
    removed.activeStateChanged(false);
}
Copy the code

The code for the detachObserver method is as follows:

// LiveData.java
@Override
void detachObserver(a) {
    // Call the removeObserver method of LifecycleRegistry
    mOwner.getLifecycle().removeObserver(this);
}
Copy the code

The code for the removeObserver method is as follows:

// LifecycleRegistry.java
@Override
public void removeObserver(@NonNull LifecycleObserver observer) {
    // Remove the observer
    mObserverMap.remove(observer);
}
Copy the code

As you can see from the code above, the system will also call this method to remove the observer, preventing a memory leak.

That’s how LiveData can sense the life cycle.

The observeForever method is also a common one.

// LiveData.java
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    / / create AlwaysActiveObserver
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing instanceof LiveData.LifecycleBoundObserver) {
        / / if the existing LiveData. LifecycleBoundObserver class instances, throw an exception
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if(existing ! =null) {
        return;
    }
    // Call the activeStateChanged method of AlwaysActiveObserver, passing true
    wrapper.activeStateChanged(true);
}
Copy the code

Take a look at the code for AlwaysActiveObserver:

// LiveData.java
private class AlwaysActiveObserver extends ObserverWrapper {

    AlwaysActiveObserver(Observer<? super T> observer) {
        super(observer);
    }

    // Override the shouldBeActive method and return true. This method is used to check whether the state is active or not, so it should always return true
    @Override
    boolean shouldBeActive(a) {
        return true; }}Copy the code

ObserveForever is used to add the specified observer to the watch list, similar to calling the Observer method, but the given LifecycleOwner state is always active, which means the observer will always receive all events, so if you want to stop observing this LiveData, Call the removeObserver method manually.

Then let’s look at the source code for three more important methods: SetValue method, postValue method and getValue method, setValue method and postValue method are used to set the value of LiveData, getValue method is used to value from LiveData, the code is as follows:

// LiveData.java
final Object mDataLock = new Object();

protected void postValue(T value) {
    boolean postTask;
    // Synchronization locks are applied to mDataLock objects
    synchronized (mDataLock) {
        // postTask uses the value NOT_SET of mPendingData to determine whether Runnable needs to be added to the message queue
        postTask = mPendingData == NOT_SET;
        // Assign value to mPendingData
        mPendingData = value;
    }
    // Determine whether Runnable needs to be added to the message queue
    if(! postTask) {Return if you do not need to add Runnable to the message queue
        return;
    }
    ArchTaskExecutor's postToMainThread method is called if Runnable needs to be added to the message queue, which will be examined below
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

// setValue must be called on the main thread
@MainThread
protected void setValue(T value) {
    // Check if it is in the main thread
    assertMainThread("setValue");
    / / mVersion since
    mVersion++;
    // Assign value to mData
    mData = value;
    // Call the dispatchingValue method
    dispatchingValue(null);
}

@SuppressWarnings("unchecked")
// The value is nullable
@Nullable
public T getValue(a) {
    Object data = mData;
    // Determine whether the value of mData is NOT_SET
    if(data ! = NOT_SET) {// If the value of mData is not NOT_SET, this value is returned
        return (T) data;
    }
    // Return null if the value of mData is NOT_SET
    return null;
}
Copy the code

Let’s look at the postToMainThread method, which looks like this:

// ArchTaskExecutor.java
@NonNull
private TaskExecutor mDelegate;

private ArchTaskExecutor(a) {
    // Create the DefaultTaskExecutor object
    mDefaultTaskExecutor = new DefaultTaskExecutor();
    // Assign mDefaultTaskExecutor to mDelegate
    mDelegate = mDefaultTaskExecutor;
}

// A method to get an ArchTaskExecutor singleton, using Double Check Locking (DCL) to implement a singleton
@NonNull
public static ArchTaskExecutor getInstance(a) {
    if(sInstance ! =null) {
        return sInstance;
    }
    synchronized (ArchTaskExecutor.class) {
        if (sInstance == null) {
            // Call the ArchTaskExecutor constructor
            sInstance = newArchTaskExecutor(); }}return sInstance;
}

@Override
public void postToMainThread(Runnable runnable) {
    // Call the postToMainThread method of DefaultTaskExecutor
    mDelegate.postToMainThread(runnable);
}
Copy the code

PostToMainThread ArchTaskExecutor inherits from TaskExecutor and is used to perform common tasks. The postToMainThread method calls the postToMainThread method of DefaultTaskExecutor.

// DefaultTaskExecutor.java
@Override
public void postToMainThread(Runnable runnable) {
    if (mMainHandler == null) {
        synchronized (mLock) {
            if (mMainHandler == null) {
                // Create Handler, passing in Looper for the main threadmMainHandler = createAsync(Looper.getMainLooper()); }}}// Add runnable to the message queue. Runnable will be executed in the main thread
    mMainHandler.post(runnable);
}
Copy the code

Then we look at the Runnable: mPostValueRunnable passed in as follows:

// LiveData.java
final Object mDataLock = new Object();

private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run(a) {
        Object newValue;
        // Synchronization locks are applied to mDataLock objects
        synchronized (mDataLock) {
            // Assign mPendingData to newValue
            newValue = mPendingData;
            // set mPendingData to NOT_SET
            mPendingData = NOT_SET;
        }
        // Call the setValue method, passing in newValuesetValue((T) newValue); }};Copy the code

PostValue finally calls setValue. If you call this method multiple times before the main thread executes the published task, only the last value will be distributed. Another thing to note is that if you call postValue first and pass in a, then setValue and pass in B, Then it will be set to B and then set to A.

The postValue method will call setValue again, and then dispatchingValue will call null, which we analyzed above, and just to be clear, if null is passed in, it will iterate through all the observers and distribute the content, Execute our logic by calling the Observer onChanged method.

digression

In the sample code, I use another Android Jetpack component, DataBinding, and call the setLifecycleOwner method of ViewDataBinding as follows:

// FirstFragment.kt
binding.lifecycleOwner = this
Copy the code

Let’s take a look at the corresponding source:

// ViewDataBinding.java
@MainThread
public void setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) {
    // Omit some code
    mLifecycleOwner = lifecycleOwner;
    if(lifecycleOwner ! =null) {
        if (mOnStartListener == null) {
            mOnStartListener = new OnStartListener(this);
        }
        // Call the addObserver method
        lifecycleOwner.getLifecycle().addObserver(mOnStartListener);
    }
    for(WeakListener<? > weakListener : mLocalFieldObservers) {if(weakListener ! =null) {
            // Call the setLifecycleOwner method of WeakListenerweakListener.setLifecycleOwner(lifecycleOwner); }}}Copy the code

The code for the setLifecycleOwner method is as follows:

// ViewDataBinding.java
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
    mObservable.setLifecycleOwner(lifecycleOwner);
}
Copy the code

LiveDataListener implements the Observer interface, so let’s look at the relevant code:

// ViewDataBinding.java
@Override
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) { LifecycleOwner owner = (LifecycleOwner) lifecycleOwner; LiveData<? > liveData = mListener.getTarget();if(liveData ! =null) {
        if(mLifecycleOwner ! =null) {
            liveData.removeObserver(this);
        }
        if(lifecycleOwner ! =null) {
            // Call LiveData's observe method
            liveData.observe(owner, this);
        }
    }
    mLifecycleOwner = owner;
}

// Based on the above analysis, the onChanged method is called when data changes
@Override
public void onChanged(@Nullable Object o) {
    ViewDataBinding binder = mListener.getBinder();
    if(binder ! =null) {
        // Notify the corresponding UI update
        binder.handleFieldChange(mListener.mLocalFieldId, mListener.getTarget(), 0); }}Copy the code

The setLifecycleOwner method is used to setLifecycleOwner, which is used to observe changes to LiveData in the Binding. If LiveData is in one of the Binding expressions, but LifecycleOwner is not set, LiveData will not be observed, and updates to it will not update the UI.

In addition, I also used Kotlin coroutine, the code is as follows:

// MainViewModel.kt
fun changeSecondContent(text: String) =
    viewModelScope.launch {
        withContext(Dispatchers.Default) {
            _secondContent.postValue(text)
        }
    }
Copy the code

The viewModelScope binds the coroutine scope to the ViewModel, which means that if the ViewModel is cleared, the coroutine scope is also cancelled. In the sample code, the MainViewModel life cycle is the same as the MainActivity life cycle. Prevent memory leaks when the coroutine performs the UI update logic after the Activity is destroyed and holds references to UI controls.

The withContext method is called and dispatchers. Default is passed, that is, the dispatchers. Default scheduler is used to call the specified suspend block, suspend until complete, and return the result. Where dispatchers. Default uses a shared background thread pool, that is to say, the logic of calling postValue method is executed in the worker thread, thus demonstrating that the worker thread sets the value of LiveData and updates the corresponding UI controls.

My GitHub: TanJiaJunBeyond

Common Android Framework: Common Android framework

My nuggets: Tan Jiajun

My simple book: Tan Jiajun

My CSDN: Tan Jiajun