Handle the life cycle; In the process of translation, I added my own understanding. If you don’t understand something, just comment.

Life cycle aware components can sense the life cycle of other components, such as activities and fragments, so that they can take actions when the life cycle state of the component changes. Life-aware components help you organize your code better, making your code lighter and more maintainable.

For components that need to respond to lifecycle changes, we typically implement operations in Activity and Fragment lifecycle methods. However, this pattern leads to unmanageable and error-prone code. With life-cycle supporting components, you can move operations that would otherwise be in a lifecycle method inside the component.

The Androidx. lifecycle package provides interfaces and classes that help us build life-cycle-aware components that can adjust their behavior based on the Activity or Fragment’s life-cycle state.

To add lifecycle aware component dependencies to your project, you can go to this page: Portal

/ / contains the ViewModel and LiveData implementation "androidx lifecycle: lifecycle - extensions: $lifecycle_version" / / or - contains only The ViewModel implementation "androidx. Lifecycle: lifecycle - ViewModel: $lifecycle_version" / / Kotlin use lifecycle - ViewModel - KTX / / implementation "androidx lifecycle: lifecycle - viewmodel - KTX: $lifecycle_version" / / or, Contains only LiveData implementation "androidx. Lifecycle: lifecycle - LiveData: $lifecycle_version" / / or, Only Lifecycle (no LiveData, ViewModel) implementation "androidx. Lifecycle: Lifecycle - runtime: $lifecycle_version" / / Kotlin Using alternative annotationProcessor kapt annotationProcessor "androidx. Lifecycle: lifecycle - compiler: $lifecycle_version" / / if you are using Java8 use this instead of lifecycle - compiler implementation "androidx. Lifecycle: lifecycle - common - Java8: $lifecycle_version" / / optional - ReactStreams support for LiveData implementation "androidx lifecycle: lifecycle - reactivestreams: $lifecycle_version" / / Kotlin Using the lifecycle - reactivestreams - KTX implementation "androidx lifecycle: lifecycle - reactivestreams - KTX: $lifecycle_version" / / Optional LiveData test testImplementation "Androidx.arch. core:core-testing:$lifecycle_version"Copy the code

If you’re using Kotlin, add the kotlin-kapt plugin

Most application components defined in the Android framework have a life cycle. The lifecycle is managed by operating system or framework code.

The component’s declaration cycle is out of our control, but we must respect the component’s life cycle, otherwise it can lead to memory leaks and even crashes.

If we have an Activity that displays device location information on the screen, the most common implementation might look like this:

Kotlin

internal class MyLocationListener(
        private val context: Context,
        private val callback: (Location) -> Unit
) {

    fun start(a) {
        // Connect to the system location service
    }

    fun stop(a) {
        // Disconnect the system location service}}class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...). {
        myLocationListener = MyLocationListener(this) { location ->
            / / update the UI}}public override fun onStart(a) {
        super.onStart()
        myLocationListener.start()
        // Manage other components that need to respond to the Activity lifecycle
    }

    public override fun onStop(a) {
        super.onStop()
        myLocationListener.stop()
       // Manage other components that need to respond to the Activity lifecycle}}Copy the code

Java

class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }

    void start(a) {
        // Connect to the system location service
    }

    void stop(a) {
         // Disconnect the system location service}}class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    @Override
    public void onCreate(...). {
        myLocationListener = new MyLocationListener(this, (location) -> {
         / / update the UI
        });
    }

    @Override
    public void onStart(a) {
        super.onStart();
        myLocationListener.start();
        // Manage other components that need to respond to the Activity lifecycle
    }

    @Override
    public void onStop(a) {
        super.onStop();
        myLocationListener.stop();
        // Manage other components that need to respond to the Activity lifecycle}}Copy the code

This seems fine for now, but in the real world, there might be other components that need to respond to the life cycle, possibly in onStart() and onStop(). One or two is fine, but if you have more of them it’s harder to maintain them in a lifecycle method.

Furthermore, this does not guarantee that our component will be started before the Activity or Fragment stops. This is especially true for long-running operations, such as the check configuration operation in onStart(). This can happen when the onStart() operation is not started and the onStop() operation is stopped.

Kotlin

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...). {
        myLocationListener = MyLocationListener(this) { location ->
            / / update the UI}}public override fun onStart(a) {
        super.onStart()
        Util.checkUserStatus { result ->
            // What if this callback is called after the activity has stopped?
            if (result) {
                myLocationListener.start()
            }
        }
    }

    public override fun onStop(a) {
        super.onStop()
        myLocationListener.stop()
    }

}
Copy the code

Java

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...). {
        myLocationListener = new MyLocationListener(this, location -> {
            / / update the UI
        });
    }

    @Override
    public void onStart(a) {
        super.onStart();
        Util.checkUserStatus(result -> {
            // What if this callback is called after the activity has stopped?
            if(result) { myLocationListener.start(); }}); }@Override
    public void onStop(a) {
        super.onStop(); myLocationListener.stop(); }}Copy the code

The Androidx.Lifecycle package provides classes and interfaces to help you solve these problems in an elastic and isolated way.

The life cycle

Lifecycle is a class that holds information about the Lifecycle state of related components (such as activities and fragments) and can be observed by other objects.

Lifecycle uses two main enumerations to track the Lifecycle status of related components.

Event

Lifecycle events emitted by the Android framework and the Lifecycle class. It corresponds to the lifecycle callbacks in activities and fragments.

State

Lifecycle class tracks the current Lifecycle status of related components.

Classes can add annotations to listen for component lifecycle events. Lifecycle will pass in an object that you will view by calling the addObserver() method as follows: Lifecycle Lifecycle

Kotlin

class MyObserver : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun connectListener(a){... }@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun disconnectListener(a){... } } myLifecycleOwner.getLifecycle().addObserver(MyObserver())Copy the code

Java

public class MyObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void connectListener(a) {... }@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void disconnectListener(a) {... } } myLifecycleOwner.getLifecycle().addObserver(new MyObserver());
Copy the code

In this example, myLifecycleOwner implements the LifecycleOwner interface.

Lifecycle owner

LifecycleOwner is a single-method interface that indicates that the class has a life cycle. It has one method that the class must implement: getLifecycle(). Look at ProcessLifecycleOwner if you want to manage the entire application process lifecycle

This interface abstracts ownership of life cycles from individual classes, such as activities and Fragments, that can share life cycles with components you write. Any class can implement the LifecycleOwner interface.

The component that implements LifecycleObserver works seamlessly with the component that implements LifecycleOwner because the owner can provide a lifecycle that the observer can register to observe.

For the example shown above, you can have MyLocationListener implement LifecycleObserver and initialize it in the Activity lifecycle method onCreate(). In this way, the MyLocationListener class can be self-contained and implement logical processing within itself in response to changes in the lifecycle. Each component responds internally to life cycle changes, making the logic of activities and fragments clear.

Kotlin

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...). {
        myLocationListener = MyLocationListener(this, lifecycle) { location ->
            / / update the UI
        }
        Util.checkUserStatus { result ->
            if (result) {
                myLocationListener.enable()
            }
        }
    }
}
Copy the code

Java

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...). {
        myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
            / / update the UI
        });
        Util.checkUserStatus(result -> {
            if(result) { myLocationListener.enable(); }}); }}Copy the code

A common use case is to avoid invoking certain callbacks if the current state of the life cycle is not good. For example, if a callback runs a Fragment transaction after saving the active state, it will trigger a crash, so we never want to invoke the callback.

To simplify this use case, the Lifecycle class allows other objects to query the current state. Through the methods: Lifecycle. State. IsAtLeast ()

Kotlin

internal class MyLocationListener(
        private val context: Context,
        private val lifecycle: Lifecycle,
        private val callback: (Location) -> Unit
) {

    private var enabled = false

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start(a) {
        if (enabled) {
            / / the connection}}fun enable(a) {
        enabled = true
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            // If you haven't already connected, do so}}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stop(a) {
        // Disconnect if connected}}Copy the code

Java

class MyLocationListener implements LifecycleObserver {
    private boolean enabled = false;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {... }@OnLifecycleEvent(Lifecycle.Event.ON_START)
    void start(a) {
        if (enabled) {
           / / the connection}}public void enable(a) {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // If you haven't already connected, do so}}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop(a) {
        // Disconnect if connected}}Copy the code

With the above implementation, our LocationListener has the ability to sense the lifecycle and perform operations accordingly. If other activities or fragments want to use it, they simply need to initialize it. All other operations are handled by the LocationListener itself.

If your library provides classes that need to be used with the Android lifecycle, lifecycle aware components are recommended. Your library can easily integrate these components without requiring manual lifecycle management on the client side.

Custom lifecycle owners

The LifecycleOwner interface is already implemented for Fragments and Activities in support library 26.1.0 and later.

If you want to create a custom class for LifecycleOwner, you can use the LifecycleOwner class, but you need to forward events to the class, as shown in the following code example:

Kotlin

class MyActivity : Activity(), LifecycleOwner {

    private lateinit var lifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)

        lifecycleRegistry = LifecycleRegistry(this)
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }

    public override fun onStart(a) {
        super.onStart()
        lifecycleRegistry.markState(Lifecycle.State.STARTED)
    }

    override fun getLifecycle(a): Lifecycle {
        return lifecycleRegistry
    }
}
Copy the code

Java

public class MyActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }

    @Override
    public void onStart(a) {
        super.onStart();
        lifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle(a) {
        returnlifecycleRegistry; }}Copy the code

Best practices for lifecycle aware components

  • Keep UI controllers (activities and fragments) as lean as possible. Let the ViewModel fetch the data, and the data changes are responded to the view via LiveData.
  • Try writing a data-driven UI where the UI controller’s responsibility is to update the view when data changes or to notify the ViewModel of user actions.
  • Put the data business logic in the ViewModel class. The ViewModel class should be positioned as a connector between the UI controller and the rest of the application. Instead of letting the ViewModel class fetch the data, let other appropriate components fetch the data. The ViewModel class simply feeds the results to the UI controller.
  • Use data binding libraries to keep views and UI controllers clean. This makes the view more declarative and reduces the updating code in the UI controller. If you prefer Java, you can use Butter Knife to reduce repetitive code.
  • If the UI is too complex, you can create a Presenter class to manage UI updates. This may be more difficult, but it’s better to manage the UI.
  • Avoid referring to the View and Activity context in the ViewModel. If the ViewModel lives longer than the Activity (in the case of configuration changes), it may cause the Activity to leak and not be collected by the garbage handler.
  • Use Kotlin coroutines to manage long-running tasks and other operations that can run asynchronously.

Use cases for lifecycle aware components

Lifecycle awareness components allow you to manage the lifecycle in a variety of situations, such as:

  • Toggle between rough and fine-grained location updates. Use lifecycle aware components to enable fine-grained location updates when the application is visible and switch to coarse-grained updates when the application is in the background.
  • Stop and enable video buffering. Start the video buffering as soon as possible using life-cycle enabled components, but delay playback until the application is fully started. Lifecycle aware components can also be used to terminate buffering when the application is destroyed.
  • Start and stop network connections. Use lifecycle aware components to update (stream) network data in real time while the application is in the foreground and automatically pause when the application is in the background.
  • Pause and resume animation drawing. Use lifecycle aware components to handle suspending animation drawing while the application is running in the background and resuming animation drawing after the application is running in the foreground.

Handling stop events

When the lifecycle is an AppCompatActivity or Fragment, the state of the lifecycle changes to CREATED, And the ON_STOP event is scheduled when onSaveInstanceState () of the AppCompatActivity or Fragment is called.

When saving the state of a Fragment or AppCompatActivity via onSaveInstanceState (), its UI is considered immutable until ON_START is called. Attempting to modify the UI after saving the state can result in inconsistent navigational state for the application, which is why the FragmentManager will throw an exception if the application runs FragmentTransaction after saving the state. For details, see: commit()

LiveData avoids this extreme situation by not calling the observer if the observer’s association life cycle is not at least STARTED. Behind the scenes, it calls isAtLeast () to determine the current state before deciding to call its observer.

Unfortunately, the onStop () method of AppCompatActivity is called after onSaveInstanceState (), which leaves a void in which the UI state is not allowed to change, but the life cycle has not yet moved to the CREATED state.

To avoid this problem, Lifecycle classes in version beta2 and earlier mark the state as CREATED and do not schedule events, so any code that checks the current state will get the true value even if the event is not scheduled until onStop () is called by the system.

Unfortunately, there are two major problems with this solution:

  • At API level 23 and below, the Android system actually savesActivityState, even if theActivityHas been by anotherActivityPartial coverage. In other words, Android system callsOnSaveInstanceState (), but not necessarily calledOnStop (). This creates a potentially long interval in which the observer considers the life cycle to be active even if its UI state cannot be modified.
  • Any toLiveDataClasses that expose similar behavior must be implementedLifecycleFixes provided in Beta 2 and below.

Note: To simplify the process and provide better compatibility with older versions, beginning with version 1.0.0-rC1, lifecycle objects are marked CREATED and ON_STOP is dispatched when onSaveInstanceState () is called without waiting for a call to onStop (). This is unlikely to affect your code, but it is important to be aware of because it does not match the order of calls in the Activity class at API level 26 and below.

The resources

Lifecycle