This is the 19th day of my participation in the Genwen Challenge

Source code analysis

Lifecycle Registrars (LifecycleRegistry)

addObserver

@Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        // Todo
        // pushParentState and popParentState before and after dispatchEvent are used to solve this problem:
        // If the observer is unregistered in onStart and then re-registered, the initial state of the re-registered observer is INITIALIZED.
        // If the ON_START callback is executed, newObserver needs to be in the CREATED state.
       // mParentStates provides the CREATED state to newObserver

    
        // start from INITIALIZED if they are not DESTROYED
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        // ObserverWithState is used to distribute events to observers
        // ObserverWithState will do the Observer conversion
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        // Add to map
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        if(previous ! =null) {
            return;
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

        // isReentrance indicates whether a new observer was added during the event distribution
    	// For example: in observer, addObserver() is called in onStart().
        booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
        ParentState, targetState, etc. are introduced to ensure that the state of the last Observer in the list cannot be greater than that of the previous Observer. State synchronization is complete.
        // Calculate the state to be distributed
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        // Progressively distribute events to targetState
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            Statefulobserver. state is less than targetState
            pushParentState(statefulObserver.mState);
            // 如果 state 为 STARTED,则 upEvent(state) 则为 ON_RESUME
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        //addObserver() takes into account the Reentrance case, where a new observer is added to the observer event distribution.
        if(! isReentrance) {// we do sync only on the top level.
             // Currently reentrant, no synchronization is performed
            sync();
        }
        mAddingObserverCounter--;
    }
Copy the code
private State calculateTargetState(LifecycleObserver observer) {
     	// Get the last added observerEntry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer); State siblingState = previous ! =null ? previous.getValue().mState : null;
    	// mParentStates is a List, which is added and removed by pushParentState() and popParentState(), respectively, in pairs before and after a dispatchEvent
    	// In this case, parentState is present: addObserver() is called at dispatchEvent, isReentranceState parentState = ! mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() -1)
                : null;
    	// The calculation here is to get the more appropriate state
    	// Consider the following case: If an observer calls addObserver in onStart(), the observer should use the STARTED state to distribute, and the current state, mState, might be RESUMED and synchronized in sync()
        return min(min(mState, siblingState), parentState);
    }
Copy the code

Instead of simply adding an Observer to a Map, addObserver first does the Observer transformation mentioned above. Then there is the “reentrant problem”. The so-called “reentrant problem” is that addObserver triggers calls to Observer lifecycle functions, which in turn invoke methods such as addObserver. So LifecycleRegistry uses the mAddingObserverCounter and mHandlingEvent variables to determine if you are in a reentrant state.

Other LifecycleOnwer

LifecycleService

ServiceLifecycleDispatcher distributed the event back to the main thread message queue, to guarantee to ensure the callback after the Service lifecycle callback to call again.

ProcessLifecycleOwner

It is used to listen for background switching of the entire application. Also use ActivityLifecycleCallback to monitor each Activity life cycle, if the onStop incident, not listening to any onStart events, The ProcessLifecycleOwner will then assume that the entire application has switched to the background, leaving a flag behind. If you listen for the onStart event and check for flags then the application is thought to be back in the foreground.

Juejin. Cn/post / 5 d15bb…

Linxiaotao. Making. IO / 2019/01/14 /…

Use ProcessLifecycle to elegantly listen to todo before and after the application

other

The paragraph below todo can be moved to another article

Best practices for lifecycle aware components

  • Try to keep your UI controllers (activities and fragments) from doing everything on their own. Instead of trying to get their own data, they should react to changes on the view through the ViewModel and observe a LiveData object.
  • Try writing a data-driven UI and make your UI controller responsible for updating the view when data changes or notifying the ViewModel of user behavior.
  • Put your data logic into the ViewModel class. The ViewModel should act as a link between your UI controller and the rest of your application. Be careful: it is not the ViewModel’s responsibility to fetch the data (such as downloading it from the network). Rather, the ViewModel should call the appropriate components to fetch the data and feed the results to the UI controller.
  • Use data binding to maintain a clean interface between your view and UI controller. This helps make your views more declarative and allows you to add minimal update logic to your UI controller. If you prefer to use the Java language for data binding, using a library such as Butter Knife can avoid eight lines of code for better abstraction.
  • If your UI is complex, consider creating a Presenter class to handle UI changes. This can be tiring, but it makes your UI components easier to test.
  • Avoid in yourViewModelDirect reference inViewActivitySuch as the context. ifViewModelIf your activity lives longer than its activity (such as a configuration change), your activity leaks memory and is hard to recycle properly by GC.

Use cases for lifecycle aware components

Lifecycle aware components make life cycle management easy in many use cases. Here are a few examples:

  • Toggle location update accuracy. Enable high-precision geolocation updates when your app is visible; Switch to low-precision updates when your application goes into the background. LiveData is a life-cycle aware component that lets your application automatically update the UI as the user moves.
  • Start and stop video buffering. Start video buffering as soon as possible, but delay playback until the app is fully started. You can also use such a component to stop the video buffering when the application is destroyed.
  • Start and stop network connections. When the application is in the foreground, enable streaming media using network connection; Automatically pauses while the application is in the background.
  • Pause and resume the animation drawable. When the application enters the background, the animation drawable is paused. When the application comes back to the foreground, restore the animation.

Handle the onStop event

Lifecycle is CREATED when Lifecycle belongs to an AppCompatActivity or Fragment. The ON_STOP event is distributed when onSaveInstanceState() of an AppCompatActivity or Fragment is called.

While the state of a Fragment or appactivity is stored in onSaveInstanceState(), its UI is considered immutable until ON_START is triggered. Attempting to change the UI after the state has been saved can result in inconsistent navigational state for your application, which is why the FragmentManager throws an exception when an application attempts to perform FragmentTransaction after the state has been saved. For more information, see Commit ().

LiveData provides out-of-the-box support for this edge case: if Lifecycle is not even STARTED to which the observer is contacted, it will not invoke that observer. Its internal implementation calls isAtLeast() first to determine whether its observer should be triggered.

The tragedy is that onStop() for AppCompatActivity is called after onSaveInstanceState(), which leads to a gap in the UI where Lifecycle is not allowed to change.

To prevent such a tragedy beta2 and earlier Lifecycle marks the state as CREATED but does not distribute events, so that any code that checks the current state will get the true value, even though the event will not be distributed until the system calls onStop().

Tragically, there are two main problems with this solution:

  • On API versions 23 and below, the Android system actually saves the state of an activity even if it is partially blocked by another activity. In other words, the Android system calls onSaveInstanceState(), but not onStop(). This leads to a potentially long gap in which the observer still thinks the life cycle is active, but the UI state cannot be changed.
  • Any attempt to expose similar behavior toLiveDataAll classes need to be implementedbeta2Or a lower versionLifecycleWorkarounds provided.

Note: To make this process simpler and backward compatible, Lifecycle objects will be marked CREATED starting with version 1.0.0-rC1, ON_STOP is distributed when onSaveInstanceState() is called, without waiting for the onStop method to be called. This should not affect your code very much, but you still need to be aware of it because it does not correspond to the order in which the Activity methods are called in API 26 and later.

The above is a translation from the official document. See Ref. 1 for the translation address.

reference

Use lifecycle-aware components to handle the lifecycle

Lifecycle for the beginning of Android architecture components

Lifecycle: Lifecycle components & Principles

The Jetpack Lifecycle

Android Arch Components (2) — Lifecycle

Android Architecture Component — Lifecycle Analysis

Lifecycle component Lifecycle

Lifecycle component Lifecycle component

The beauty of Android architecture -Lifecycle