preface

What is a Lifecycle aware component?

Life-cycle-aware components perform operations in response to changes in the life-cycle state of another component, such as an Activity or Fragment. These components help you write more organized and often leaner code that is easier to maintain.

Lifecycle is what?

Lifecycle is a class that stores information about the Lifecycle state of a component, such as an Activity or Fragment, and allows other objects to observe that state.

What are the pain points it addresses?

Most application components defined in the Android framework have a life cycle. The lifecycle is managed by the framework code running in the operating system or process. They are at the heart of how Android works, and apps must follow them. Failure to do so can cause memory leaks and even application crashes.

【 this series of articles (JAVA/KOTLIN) demo cases are stored in making the repository in ArchitecturalComponentExample 】

Use the meaning of Lifecycle

Speaking of the Activity lifecycle, It is not hard to think of Application a method registerActivityLifecycleCallbacks () can register lifecycle callback, And activities with build.version.sdk_int >= build.version_codes. Q extend this method to get the Activity lifecycle state:

registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { @Override public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { Log.i("loglog", "onActivityCreated"); } @Override public void onActivityStarted(@NonNull Activity activity) { Log.i("loglog", "onActivityStarted"); } @Override public void onActivityResumed(@NonNull Activity activity) { Log.i("loglog", "onActivityResumed"); } @Override public void onActivityPaused(@NonNull Activity activity) { Log.i("loglog", "onActivityPaused"); } @Override public void onActivityStopped(@NonNull Activity activity) { Log.i("loglog", "onActivityStopped"); } @Override public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) { Log.i("loglog", "onActivitySaveInstanceState"); } @Override public void onActivityDestroyed(@NonNull Activity activity) { Log.i("loglog", "onActivityDestroyed"); }});Copy the code

Similarly, we can implement lifecycle listening in an Activity by simply using lifecycle callbacks such as onCreate() and onResume().

For specific cases, please refer to official documents

It is not hard to see that there are some problems with writing this way:

  • Lifecycle management is centralized, and not all lifecycle callbacks are needed
  • If more than one function is done in the same lifecycle callback, the amount of code in the same callback method can be very high, resulting in significant maintenance costs
  • There is no guarantee that a component will start before an Activity or Fragment stops. This is especially true when we need to run an operation for a long time, such as some configuration check in onStart(). This can lead to a race condition in which the onStop() method ends before onStart(), making the component persist longer than it needs to.

Lifecycle can provide a separate Lifecycle observer for each of your functions, so that there is less coupling between the code and the Activity/Fragment, and the Lifecycle observer of each function can be reused, and the separation of functionality components can make your application more extensible.

Using the Lifecycle

Introduction of depend on

When this document is written, the stable dependent version is 2.2.0. The next candidate preview version is 2.3.0-RC01. Check the recommended version of official documents before importing the document.

Dependencies {def lifecycle_version = "implementation" def arch_version = "2.1.0 "Androidx. Lifecycle: lifecycle - viewmodel: $lifecycle_version" / / LiveData support implementation "Androidx. Lifecycle: lifecycle - livedata: $lifecycle_version" / / Lifecycles only (not including the ViewModel and livedata support) implementation "Androidx. Lifecycle: lifecycle - runtime: $lifecycle_version" / / save the ViewModel state module implementation "Androidx. Lifecycle: lifecycle - viewmodel - savedstate: $lifecycle_version" / / comment annotationProcessor processor "Androidx. Lifecycle: lifecycle - compiler: $lifecycle_version" / / - if you use other Java8, Use the following code instead of lifecycle - compiler implementation "androidx. Lifecycle: lifecycle - common - java8: $lifecycle_version" / / Optional - implement LifecycleOwner assistant in a service implementation "androidx. Lifecycle: lifecycle - service: $lifecycle_version" / / optional - ProcessLifecycleOwner provide a life cycle for the entire application process implementation "androidx. Lifecycle: lifecycle - process: $lifecycle_version" / / optional - ReactiveStreams support LiveData implementation "androidx. Lifecycle: lifecycle - ReactiveStreams: $lifecycle_version" / / optional - LiveData test assistant testImplementation "Androidx.arch. core:core-testing:$arch_version"}Copy the code

Not all contents of the preceding dependency libraries need to be imported. You need to import corresponding dependencies based on actual requirements.

For example, if you simply want to use Lifecycle management capabilities, you can introduce dependencies like this:

Dependencies {def lifecycle_version = "implementation "Androidx. Lifecycle: lifecycle - runtime: $lifecycle_version" / / is responsible for the process (application) implementation of the life cycle 'androidx.lifecycle:lifecycle-process:$lifecycle_version' }Copy the code

LifecycleObserver

To observe the lifecycle of an interface component, write your LifecycleObserver and add it to the LifecycleOwner watch queue (collection) of interface components. You can define lifecycle events in your LifecycleObserver that you are interested in. For example, if you need to control the camera to turn on or off when the screen is on/off, you can do this:

public class CameraLifecycleObserver implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void initCamera(a){
        Log.i("loglog"."ON_CREATE initializes camera");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void openCamera(a) {
        Log.i("loglog"."ON_RESUME Open camera");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void closeCamera(a) {
        Log.i("loglog"."ON_PAUSE closes camera");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy(a){
        Log.i("loglog"."ON_DESTROY Destroys resource"); }}Copy the code

Of course, if you want to take advantage of other lifecycles, or actively retrieve the lifecycle of a component, you can either pass the lifecycle component into the CameraLifecycleObserver component to retrieve the current lifecycle:

public class CameraLifecycleObserver implements LifecycleObserver {

    private Lifecycle mLifecycle = null;
    Of course, LifecycleOwner and other type parameters can also be passed here
    public CameraLifecycleObserver(Lifecycle lifecycle){
        mLifecycle = lifecycle;
    }

    // You should call both apis in the method body when appropriate, not necessarily ON_ANY
    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    public void onAny(a){
        // Get the current state
        Lifecycle.State currentState = mLifecycle.getCurrentState();
        // At least onStart has been executed
        booleanhasStarted = currentState.isAtLeast(Lifecycle.State.STARTED); }}Copy the code

Component implements LifecycleOwner

With the observer written, we can pass an instance of the observer to the LifecycleOwner, and there are two things you can do about the LifecycleOwner:

  • You are using the Androidx support library and version> = 26.1.0, Fragment and Activity implement LifecycleOwner interface, which mainly refers to inherit fromComponentActivityAnd subclasses of Activity and inherit fromandroidx.fragment.app.FragmentThe fragments.
  • In other cases, you’ll need to implement LifecycleOwner yourself and rewrite itgetLifecycle()Method and manually distribute the lifecycle you need:
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

Pass the observer to the LifecycleOwner

Once you have the LifecycleOwner object, you can hand it the LifecycleObserver that you implement. The LifecycleObserver will notify your LifecycleOwner when lifecycle change events occur.

getLifecycle().addObserver(newCameraLifecycleObserver(... params));Copy the code

Let’s take a look at the result:

I/ Loglog: ON_CREATE Initialize the camera I/ Loglog: onActivityStarted I/ Loglog: onActivityResume Open the camera I/ Loglog: ON_PAUSE Disable camera I/ LOglog: onActivityPaused I/ LOglog: onActivityStopped I/ LOglog: ON_DESTROY Destroy resource I/loglog: onActivityDestroyedCopy the code

Add life cycle events to the process

If you want to listen for changes before and after your application, you can check out this section. In the past, to see if the application is foreground, you can do this:

public boolean inAppOnForeground(Context context) {
    try {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
        String packageName = context.getPackageName();
        if(activityManager ! =null) {
            List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
            if (appProcesses == null) {
                return false;
            }
            for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
                if (packageName.equals(appProcess.processName)
                        && appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                    return true; }}}}catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}
Copy the code

So you can only know if your app is foreground, but you can’t know when it’s foreground and when it’s background, which might not be a good idea if you need to know exactly when your app is going into the background to do something. . Of course you can also through the Application registerActivityLifecycleCallbacks () to monitor the activity to start and quit, for its start-up and exit count, count to zero when exit can be regarded as Application background, when start counting do Application foreground for 1 is visible, Emmmm, it’s a lot of work when I think about it

Let’s take a look at the use of Lifecycle how to do this simple thing (to introduce rely on androidx. Lifecycle: Lifecycle – process: $last_version) :

  • Write a lifecycle observer
  • Add a lifecycle observer to your Application
public class ProcessLifecycleObserver implements LifecycleObserver {
    // a scheme to mark the state of the front and background
    private boolean isForeground = false;

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onForeground(a) {
        Log.i("loglog"."onForeground: ON_START");
        isForeground = true;
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onBackground(a) {
        Log.i("loglog"."onBackground: ON_STOP");
        isForeground = false;
    }
    // A way to get the state of the front and back
    public boolean isForeground(a) {
        returnisForeground; }}public class MyApplication extends Application {

    private ProcessLifecycleObserver observer;

    @Override
    public void onCreate(a) {
        super.onCreate();

        observer = new ProcessLifecycleObserver();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(observer);
    }
    // A way to get the state of the front and back
    public boolean isForeground(a) {
        returnobserver.isForeground(); }}Copy the code

This is simple to complete the application of the front and background switch monitoring, as well as the front and background status of the query ~

Best practices for life-cycle aware components

To learn about best practices for lifecycle aware building, please click on the official documentation for details

The introduction to working with Lifecycle and Jetpack components such as LiveData will be written at the end of the architecture Component Basics series, until then please refer to the official documentation