The principle of overview

Lifecycle is mainly used for monitoring the state of activities, fragments and other stative components. One of the most important functions is to remove a large number of life-cycle related callback functions in the original activities and fragments out of the View layer file. From the design point of View, Lifecycle is mainly used for monitoring the state of activities, fragments and other stative components. Make MVVM View layer file structure more clear, simple, simplify the task of View layer, make the code more clear, easy to maintain.

Lifecycle implementation listening can be implemented in two main ways, in versions below API29 it is mainly method one and in versions of API29+ it is method two.

  1. Like Glide, it uses a Fragment dedicated to reporting state. When this particular blank Fragment is inserted into a host Activity, it can retrieve the host’s life-cycle state changes.
  2. implementationApplication.ActivityLifecycleCallbacks, listen for changes related to the lifecycle.

The general steps are as follows:

  • Declare your own listening component :MyUtil implementationLifecycleObserver interface.
  • Declare life cycle callback functions with annotations:
@onlifecycleEvent (Lifecycle.event.on_create) private void fun1(){// ON_CREATE needs to do things}Copy the code
  • Called in mainactivity.java:
getLifecycle().addObserver(new MyUtil());
Copy the code

Obviously in this model Lifecycle itself is only the source of an event and MyUtil, the listener that we implement ourselves, is the observer. We register our tools with Lifecycle and once Lifecycle has received notification of changes to its lifecycle, lifecycle notifies a series of observers to update:

Lifecycle itself is more like a proxy, our utility class doesn’t need to do the listening itself, so this can really be seen as a synthesis of the two observer patterns, and Lifecycle in the middle is an interface that the system provides for us to get callbacks. We just need to register our Observer. As a result, the process of analyzing Lifecycle is clearly broken down into two sub-problems:

Question 1. How does MyUtil(LifecycleObserver) listen on lifecycle?

Question 2. How does Lifecycle listen for host lifecycle changes?

Constitute a

Lifecycle is made up of:

  • LifecycleA component (Activity, Fragment) may have its own Lifecycle.
  • LifecycleOwner: Lifecycle holder, a component (Activity, Fragment)
  • LifecycleObserver: LifecycleObserver is a component whose lifecycle lifecycle needs to be observed. Lifecycle addObserver is used to register and listen to LifecycleObserver. This allows the corresponding LifecycleObserver class to get life-cycle related callbacks.
  • Event: life cycle callback methods, such as ON_CREATE, ON_START, etc.
  • State: When an Event occurs, State will change. For example, when ON_CREATE Event occurs, State will change from INITIALIZED to CREATED, as shown in the State transition diagram in [Model].
    • INITIALIZED: has just been initialized.
    • CREATED: after ON_CREATE, after ON_STOP.
    • STARTED: after ON_START, after ON_PAUSE.
    • RESUMED: ON_PAUSE after ON_RESUMEbefore.
    • ON_DESTORYED: has not been created or destroyed after ON_DESTROY.

model

// Corresponding state transition function
@NonNull
public State getTargetState(a) {
  	// Enumeration class. This identifies an event such as ON_CREATE, ON_STOP, etc.
    switch (this) {
        // For ON_CREATE and ON_STOP events, both correspond to CREATED states. (Both points to CREATED)
        case ON_CREATE:
        case ON_STOP:
            return State.CREATED;
        case ON_START:
        case ON_PAUSE:
            return State.STARTED;
        case ON_RESUME:
            return State.RESUMED;
        case ON_DESTROY:
            return State.DESTROYED;
        case ON_ANY:
            break;
    }
    throw new IllegalArgumentException(this + " has no target state");
}
Copy the code

The source code

1. addObserver(observer)

LifecycleOwner is the source of events, and both fragments and activities are lifecycleOwners. In other words, the two produce a series of life-cycle related events.

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner
Copy the code

LifecycleOwner provides a single method, and, in the ComponentActivity class, Lifecycle is used in an implementation class: mLifecycleRegistry

public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle(a);
}

private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
Copy the code
//LifecycleRegistry.java
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    enforceMainThreadIfNeeded("addObserver");// Main thread assertion
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;// If mState is destroyed, mark it as destroyed; If they are other (all valid), mark them as initialized.
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);// Pass in a custom observer (non-observed) and state.
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);// Try to put it into a collection of observer objects maintained by the observer (to prevent multiple registrations if none exist). If so, return value of the existing value; If no PUT exists, null is returned.
  	// If the same observer existed before, return;
    if(previous ! =null) {
        return;
    }
  	// Retrieve lifecycleOwner object, which is usually an Activity or Fragment. Note that lifecycleOwner is referenced by WeakReference
      
       . It is in the constructor of LifecycleRegistry that the value is injected.
      
   	//private final WeakReference<LifecycleOwner> mLifecycleOwner;
  
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
  
  	// If it is empty, the object has been reclaimed and returns.
    if (lifecycleOwner == null) {
        // it is null we should be destroyed. Fallback quickly
        return;
    }

    booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
		// Number of observers being registered +1
  	
  	//ENUM Comparison between classes. Equality between classes returns 0. This loop serves to append the previous lifecycle event dispatch (stickiness)
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
      	// The internal implementation of this line is: mparentstates.add (state); MParentStates is an ArrayList that stores "old" messages. For example, if you click the button to register a listener in the running state (create, start, resume), pushParentState: stateFulobServer. mState is INITIALIZED.
        pushParentState(statefulObserver.mState);
      	INITIALIZED. The Event fetched from upFrom is "ON_CREATE", but the onCreate state is already gone.
        final Event event = Event.upFrom(statefulObserver.mState);
        if (event == null) {
            throw new IllegalStateException("no event up from " + statefulObserver.mState);
        }
      	// Note that the ON_CREATE and other callbacks in our instance are executed in this step (Figure 1), which updates the state and issues events. When this code is passed, stateFulobServer.mstate becomes CREATED
        statefulObserver.dispatchEvent(lifecycleOwner, event);
      	
      	// Corresponds to pushParentState. After pushParentState is deleted, the length of parentState is 0.
        popParentState();
      
      	
        targetState = calculateTargetState(observer);
      	// StateFulobServer. mState is CREATED and targetState is updated to RESUME.
    }
  	
    if(! isReentrance) {// we do sync only on the top level.
        sync();
    }
    mAddingObserverCounter--;
}
Copy the code

And then the second round of code, which is actually similar to the first round, goes from Event to ON_CREATE to ON_START, and then sends out the ON_START Event. ON_RESUME similarly. The general process is when you add an Observer. The State FulobServer is the main one. No matter what the State of the Activity is, the initialState is INITIALIZED when it enters. Then, according to the State (State, such as CREATED), the event. upFrom function is used to fetch the Event (Event, CREATED). ON_CREATE for example), and then, statefulObserver dispatchEvent (lifecycleOwner, event); The statefulObserver is updated, and so on.

A few key expansions of the above code:

private State calculateTargetState(LifecycleObserver observer) {
  	
  	//mObserverMap is line 7 of the addObserver trunk above:
  	//ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
  	// This is the only join call to the Map.
	
  	/ / remove the nearby ObserverWithState FastSafeIterableMap, comments saying is: Poor 's man LinkedHashMap
  	/ / LifecycleObserver as you can see, in the androidx.core.app.Com ponentActivity ComponentActivity implements this interface.
  	// So, the Map is an Activity with State(one State, one LifecycleEventObserver) structure:
  	
    Map.Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);

  	// If not null, then set siblingState to mState else NULL of the object stored in PreviousState siblingState = previous ! =null ? previous.getValue().mState : null;
  	// If parentState is present, get State else NULL for the last parentStateState parentState = ! mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() -1)
            : null;
  	// Take the minimum value among mState, siblingState, and parentState.
    return min(min(mState, siblingState), parentState);
}


//statefulObserver.dispatchEvent(lifecycleOwner, event);        
void dispatchEvent(LifecycleOwner owner, Event event) 
   // Obtain the state according to event (ENUM). This is the same as the state graph above.
   State newState = event.getTargetState();
	 // select the minimum state
   mState = min(mState, newState);
   // Update the status and respond to the callback
   mLifecycleObserver.onStateChanged(owner, event);
	 // Set the new state
   mState = newState;
}

Copy the code

2. sync()

private void sync(a) {
  	// Life cycle holders such as activities and fragments.
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
  	// Check whether it has been collected
    if (lifecycleOwner == null) {
        throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                + "garbage collected. It is too late to change lifecycle state.");
    }
  	// Loop if elements in the mObserverMap are not fully synchronized, synchronizing the state of all saved observers.
    while(! isSynced()) {/ / tag if there is a new event, when moveToState is invoked, satisfy the conditions (mHandlingEvent | | mAddingObserverCounter! = 0), this property is set to true.
      	// The two conditions are: 1 whether the event is being processed, and 2 whether the newly added observer is being processed.
        mNewEventOccurred = false;
        // Compare mState to the oldest element state in the mObserverMap, and if it is smaller (the smallest is DESTROY, INITIALIZED, all the way to RESUMED), it takes a long time to update backward from the earliest element to the RESUMED map. For example, CREATED < RESUMED
        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
          	// backpropagation
            backwardPass(lifecycleOwner);
        }
        Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
      	// If no new events occur (no moveToState is triggered during this time), the latest observer is not empty, and the current component state precedes the latest component state.
      	For example, mState = newest. MState = CREATED, then forward propagation is triggered.
        if(! mNewEventOccurred && newest ! =null
                && mState.compareTo(newest.getValue().mState) > 0) {
          	// Forward propagation
            forwardPass(lifecycleOwner);
        }
      	// In this loop, all Observer states are synchronized.
    }
    mNewEventOccurred = false;
}

private boolean isSynced(a) {
  	if (mObserverMap.size() == 0) {
    	return true;
  	}
  	State eldestObserverState = mObserverMap.eldest().getValue().mState;
  	State newestObserverState = mObserverMap.newest().getValue().mState;
  	// Check whether the latest entry is equal to the current state.
  	return eldestObserverState == newestObserverState && mState == newestObserverState;
}
Copy the code
/ / forwardPass similarly;
private void backwardPass(LifecycleOwner lifecycleOwner) {
  	/ / the iterator
    Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
  	// In forwardPass:
    //Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
    // mObserverMap.iteratorWithAdditions();
  	// Iterate without a new event (moveToState triggered).
    while(descendingIterator.hasNext() && ! mNewEventOccurred) { Map.Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next(); ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
          	// Similar to the logic in addObserver, synchronization actively calls back the status of other listeners that are lagging.
            Event event = Event.downFrom(observer.mState);
            if (event == null) {
                throw new IllegalStateException("no event down from "+ observer.mState); } pushParentState(event.getTargetState()); observer.dispatchEvent(lifecycleOwner, event); popParentState(); }}}Copy the code

3. SetCurrentState, moveToState

Methods in this category are used for external calls that will be used for the transition of state to Lifecycle. For example, we can explicitly call the setCurrentState method throughout the lifecycle of an Activity to flag (notify) the lifecycle state. Once the tag is complete, sync is triggered to synchronize all observer states.

    @MainThread
    public void setCurrentState(@NonNull State state) {
        enforceMainThreadIfNeeded("setCurrentState");// Assert the main thread
        moveToState(state);
    }

    /**
     * Sets the current state and notifies the observers.
     * <p>
     * Note that if the {@codecurrentState} is the same state as the last call to this method, * Calling this method has no effect. * *@param event The event that was received
     */
    public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        enforceMainThreadIfNeeded("handleLifecycleEvent");// Assert the main thread
        moveToState(event.getTargetState());
    }

    private void moveToState(State next) {
      	// The same state is invalid.
        if (mState == next) {
            return;
        }
        mState = next;
      	// If an event is being processed, or if there is a newly added Observer (the number is not zero), then a new event is currently present.
        if(mHandlingEvent || mAddingObserverCounter ! =0) {
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;// The tag is handling events, sort of like a lock
        sync();// synchronize (forward propagation)
        mHandlingEvent = false;/ / end
    }


Copy the code

Listening to the

So let’s start with moveToState, which has three calls.

@Deprecated
@MainThread
public void markState(@NonNull State state) {
    enforceMainThreadIfNeeded("markState");
    setCurrentState(state);
}

@MainThread
public void setCurrentState(@NonNull State state) {
    enforceMainThreadIfNeeded("setCurrentState");
    moveToState(state);
}

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    enforceMainThreadIfNeeded("handleLifecycleEvent");
    moveToState(event.getTargetState());
}
Copy the code

MarkState has been marked as @deprecated, but we can find one call to it: onSaveInstanceState in the ComponentActivity under package Androidx.core. app still keeps this method called.

package androidx.core.app;

@CallSuper
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    mLifecycleRegistry.markState(Lifecycle.State.CREATED);//
    super.onSaveInstanceState(outState);
}
Copy the code

SetCurrentState is in package Androidx. activity; ComponentActivity is referenced in:

package androidx.activity;

@CallSuper
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    Lifecycle lifecycle = getLifecycle();
    if (lifecycle instanceof LifecycleRegistry) {
        ((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED);//
    }
    super.onSaveInstanceState(outState);
    mSavedStateRegistryController.performSave(outState);
}
Copy the code

As for handleLifecycleEvent:

Obviously handleLifecycleEvent and lifecyle have a close relationship in AppcompatActivity.

For example, in the onCreate method, there are:

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);

        if(savedInstanceState ! =null) {
           // If the Activity is being rebuilt, omit the following. }if (mPendingFragmentActivityResults == null) {
            mPendingFragmentActivityResults = new SparseArrayCompat<>();
            mNextCandidateRequestIndex = 0;
        }

        super.onCreate(savedInstanceState);

        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);// Send events
        mFragments.dispatchCreate();
    }

Copy the code

Whenever our Activity parent’s FragmentActivity method: onCreate is called back, it must trigger the execution of handleLifecycleEvent(), which makes listening very simple.

However, in the androidx.activity.Com ponentActivity; In, there is a very special piece of code:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedStateRegistryController.performRestore(savedInstanceState);
    ReportFragment.injectIfNeededIn(this);//
    if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}Copy the code
public static void injectIfNeededIn(Activity activity) {
    if (Build.VERSION.SDK_INT >= 29) {
        / / On 29 + API (Android 10.0 +), we can directly register the correct lifecycle to monitor, internal will directly to realize to monitor: mActivityLifecycleCallbacks in the Activity class, add a Callback: mActivityLifecycleCallbacks.add(callback);
        activity.registerActivityLifecycleCallbacks(
                new LifecycleCallbacks());
    }
		
    android.app.FragmentManager manager = activity.getFragmentManager();
    if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
      	// Notice here that we added a new ReportFragment() to the current Activity.
        manager.beginTransaction().add(newReportFragment(), REPORT_FRAGMENT_TAG).commit(); manager.executePendingTransactions(); }}Copy the code

Take any Fragment lifecycle function as an observation and enter the Dispatch () method.

@Override
public void onStart(a) {
    super.onStart();
    dispatchStart(mProcessListener);
    dispatch(Lifecycle.Event.ON_START);
}

@Override
public void onResume(a) {
    super.onResume();
    dispatchResume(mProcessListener);
    dispatch(Lifecycle.Event.ON_RESUME);
}

@Override
public void onPause(a) {
    super.onPause();
    dispatch(Lifecycle.Event.ON_PAUSE);
}
Copy the code

In the Dispatch method, it is found that the activity as LifecycleOwner gets its Lifecycle event processing.

@SuppressWarnings("deprecation")
static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
    if (activity instanceof LifecycleRegistryOwner) {
        ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);//
        return;
    }

    if (activity instanceof LifecycleOwner) {
        Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
            ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);//}}}Copy the code

LifecycleRegistryOwner is a subclass of the LifecycleOwner interface, and you can see that the return value is different. Obviously, when the Activity life cycle changes, the Fragment life cycle changes accordingly. HandleLifecycleEvent in the ReportFragment life cycle function is a very clever way to implement this function. This is very similar to Glide’s implementation, which uses a blank RequestManagerFragment.

However, in API29+, the program will walk this code:

public static void injectIfNeededIn(Activity activity) {
    if (Build.VERSION.SDK_INT >= 29) {
        // On API 29+, we can register for the correct Lifecycle callbacks directly
        LifecycleCallbacks.registerIn(activity);
    }
    / /...
}

static class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks {

  	// There are omissions
    static void registerIn(Activity activity) {
        activity.registerActivityLifecycleCallbacks(new LifecycleCallbacks());
    }
    @Override
    public void onActivityPostCreated(@NonNull Activity activity,
            @Nullable Bundle savedInstanceState) {
        dispatch(activity, Lifecycle.Event.ON_CREATE);
    }
    @Override
    public void onActivityPostStarted(@NonNull Activity activity) {
        dispatch(activity, Lifecycle.Event.ON_START);
    }
    @Override
    public void onActivityPostResumed(@NonNull Activity activity) {
        dispatch(activity, Lifecycle.Event.ON_RESUME);
    }
    @Override
    public void onActivityPrePaused(@NonNull Activity activity) {
        dispatch(activity, Lifecycle.Event.ON_PAUSE);
    }
    @Override
    public void onActivityPreStopped(@NonNull Activity activity) {
        dispatch(activity, Lifecycle.Event.ON_STOP);
    }
    @Override
    public void onActivityPreDestroyed(@NonNull Activity activity) { dispatch(activity, Lifecycle.Event.ON_DESTROY); }}Copy the code

At the same time, Api29+ models will also go to: insert a ReportFragment. In theory, through the Application. The ActivityLifecycleCallbacks callback will have to register to listen, as to why this design is not clear. But the dispatch method to dispatch the event:

private void dispatch(@NonNull Lifecycle.Event event) {
    if (Build.VERSION.SDK_INT < 29) {
        dispatch(getActivity(), event);//TAG}}Copy the code

It limits the listening generated by the Fragment lifecycle callback to being dispatched only when Api<29, so no two dispatches occur. The dispatch at the TAG is a static method, and notice that THE DISPATCH from API29+ is called directly from that static method.

static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
    if (activity instanceof LifecycleRegistryOwner) {
        ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
        return;
    }

    if (activity instanceof LifecycleOwner) {
        Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
        if (lifecycle instanceofLifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); }}}// The call in API29 follows the static method above.
@Override
public void onActivityPostStarted(@NonNull Activity activity) {    
	  dispatch(activity, Lifecycle.Event.ON_START);
}
Copy the code

Whether API29 following through fragments to monitor or API29 above, through the Application. The ActivityLifecycleCallbacks monitor, walk is lifecycle. HandleLifecycleEvent () method. This is why handleLifecycleEvent was mentioned above with a large number of calls:

other

1. Application.ActivityLifecycleCallbacks

This interface contains a lot of the callback function, and the three different to the callback function in the daily development, here is more detailed, divided into three groups, each group and distinguish between pre and post, plus a onActivitySaveInstanceState, whenever the Activity life cycle change occurs, The callback function is called back to and the parameter is the changed Activity. We can customize a class implements this interface, and then enclosing registerActivityLifecycleCallbacks (callbacks); Just register. This class also allows for more flexible Activity instance control. Most of the events are handled in the POST section, not the Pre.

@Override
public void onActivityResumed(@NonNull Activity activity) {}@Override
public void onActivityPostResumed(@NonNull Activity activity) {
    dispatch(activity, Lifecycle.Event.ON_RESUME);// Issue events to listeners (MyUtils class, etc.)
}
Copy the code

conclusion

Starting with listening, in versions later than API29, a ReportFragment is added to the Activity. When the lifecycle of the Fragment changes, the time will be sent to update the lifecycle. Lifecycle notifies the LifecycleObserver of Lifecycle updates uniformly; While API29 +, can directly through the monitoring Application. ActivityLifecycleCallbacks interface, to obtain the Activity state, at the same time also can insert ReportFragment, However, dispatch in the life cycle of the Fragment reporting the state will not take effect. Both the Fragment and the Activity add a listener and output before and after onStop. The order of callbacks in the two methods (API29+ and API29 below) is also different.

Attachment: part of the official document

Handle ON_STOP events (Google links may not open)

1. Handle the ON_STOP event

If Lifecycle is an AppCompatActivity or Fragment, then calling onSaveInstanceState() for AppCompatActivity or Fragment, Lifecycle will change the state to CREATED and an ON_STOP event will be dispatched.

After saving the state of a Fragment or appactivity with onSaveInstanceState(), the interface is considered immutable until ON_START is called. If you try to modify the interface after saving the state, it is likely that the application’s navigational state will be inconsistent, so when the application runs FragmentTransaction after saving the state, the FragmentManager will throw an exception. ** For more details, see Commit ().

LiveData itself prevents this extreme situation by avoiding calling its observer when its Lifecycle is not at least STARTED. Behind the scenes, it calls isAtLeast() before deciding to call its observer.

Unfortunately, the onStop() method for AppCompatActivity will be called after onSaveInstanceState(), which leaves a gap that doesn’t allow the interface state to change, but Lifecycle hasn’t moved to the CREATED state.

To prevent this, the Lifecycle class in Beta2 and earlier marks the state as CREATED without dispatching events, so that code that checks the current state will get the actual value even if the event is not dispatched (until the system calls onStop()).

Unfortunately, there are two main problems with this solution:

  • At API 23 and below, the Android system actually saves the state of an Activity even if part of it is overwritten by another Activity. In other words, the Android system callsonSaveInstanceState(), but not necessarily calledonStop(). This can result in long intervals in which the observer still perceives the life cycle to be active, although its interface state cannot be modified.
  • Any toLiveDataClasses that expose similar behavior must be implemented byLifecycleversionbeta 2And lower versions of the solution.

Note: To simplify this process and make it more compatible with earlier versions, from 1.0.0-rC1 Lifecycle object is marked as CREATED and ON_STOP is dispatched when onSaveInstanceState() is called, Instead of waiting for the onStop() method to be called. This is unlikely to affect your code, but you need to be aware of it because it does not correspond to the order of calls in API 26 and lower Activity classes.

2. Best practices for lifecycle aware components

  • Keep interface controllers (activities and fragments) as lean as possible. Instead of trying to get their own data, they should do so using the ViewModel and observe the LiveData object to reflect changes into the view.
  • Try to write data-driven interfaces where the interface controller’s responsibility is to update the view as the data changes, or to notify the ViewModel of user actions.
  • Put the data logic in the ViewModel class. The ViewModel should act as a connector between the interface controller and the rest of the application. Note, however, that the ViewModel is not responsible for fetching data (for example, from the network). However, the ViewModel should call the corresponding component to get the data and then feed the results to the interface controller.
  • Use data binding to maintain a clean interface between views and interface controllers. In this way, you can make your views more declarative and minimize the amount of updating code that needs to be written in activities and fragments. If you prefer to do this in the Java programming language, use a library such as Butter Knife to avoid boilerplate code and achieve better abstraction.
  • If the interface is complex, consider creating a Presenter class to handle changes to the interface. This can be a daunting task, but doing so makes interface components easier to test.
  • To avoid theViewModelReferenced in theViewActivityThe context. ifViewModelExisting longer than an Activity (in the case of a configuration change), the Activity will leak and not be properly disposed of by the garbage collector.
  • Use Kotlin coroutines to manage long-running tasks and other operations that can run asynchronously.