preface

Nice to see you again. Here comes the series of “Strange techniques and Lewd Tricks”. This series introduces some “SAO operations”, which may not be suitable for production, but can open up ideas

A few days ago, I saw a discussion in the group about maintaining the activity stack to listen to the application switch between the front and back. Actually simple listeners Taiwan before and after switching does not need to maintain the activity stack, and now is the mainstream approach is to use registerActivityLifecycleCallbacks. Today I’ll look at using ProcessLifecycleOwner to do just that

Lifecycle – the process library

The Android Jetpack Lifecycle component has an optional library, Lifecycle – Process, which provides a ProcessLifecycleOwner for the entire app process

Lifecycle – process introduced

The library is very simple, with only four files

lifecycle-process

ProcessLifecycleOwnerInitializer using ContentProvider to Context, used for initialization

init

EmptyActivityLifecycleCallbacks for Application. ActivityLifecycleCallbacks implementation class, inside is empty

EmptyActivityLifecycleCallbacks

LifecycleDispatcher hooks the host’s life cycle events through ReportFragment

The core logic is all in ProcessLifecycleOwner

ProcessLifecycleOwner

This class provides for the lifecycle of the entire app process

Think of it as a LifecycleOwner for all activities, where Lifecycle.event.on_create is distributed only once and Lifecycle.event.on_destroy is never distributed

Other lifecycle events will be distributed according to the following rules:

The ProcessLifecycleOwner will distribute Lifecycle.event.on_start and Lifecycle.event.on_resume events (when the first activity moves to these events)

Lifecycle.event.on_pause and lifecycle.event.on_stop will be delayed until the last activity has moved into these states long enough for the delay to occur, To ensure that no events are distributed after the activity is rebuilt due to actions such as configuration changes

This is useful for scenarios where listening applications switch back and forth and millisecond precision is not required

ProcessLifecycleOwner Source code parsing

From the figure above we know that ProcessLifecycleOwner implements the LifecycleOwner interface

Due to the initialization time in ProcessLifecycleOwnerInitializer introduced into Context, Therefore ProcessLifecycleOwner in attach approach with the help of Context to get the Application instance, and calls the registerActivityLifecycleCallbacks

void attach(Context context) {
    mHandler = new Handler();
    mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    Application app = (Application) context.getApplicationContext();
    app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks()
 @RequiresApi(29)  @Override  public void onActivityPreCreated(@NonNull Activity activity,  @Nullable Bundle savedInstanceState) {  // We need ProcessLifecycleOwner to get ON_START and ON_RESUME just before the first activity's LifecycleOwner started/resumed.  // The LifecycleOwner of an activity gets the started/resumed state by adding a callback registered for the activity to onCreate().  // By adding our own callback for the activity registry in onActivityPreCreated(), we get the callback first, while still having the correct relative order compared to the onStart()/ onResume() callback for the activity   activity.registerActivityLifecycleCallbacks(new EmptyActivityLifecycl  @Override  public void onActivityPostStarted(@NonNull Activity activity) {  activityStarted();  }  @Override  public void onActivityPostResumed(@NonNull Activity activity) {  activityResumed();  }  });  }  @Override  public void onActivityCreated(Activity activity, Bundle savedInstanceStat / / only in API29Before using ReportFragment, after that, we can use the ReportFragment in onActivityPreCreated()OnActivityPostStarted and onActivityPostResumed callbacks registered in if (Build.VERSION.SDK_INT < 29) {  ReportFragment.get(activity).setProcessListener(mInitializationLi  }  }  @Override  public void onActivityPaused(Activity activity) {  activityPaused();  }  @Override  public void onActivityStopped(Activity activity) {  activityStopped();  }  }); } Copy the code

The number of Started and Resumed is maintained internally

private int mStartedCounter = 0;
private int mResumedCounter = 0;
private boolean mPauseSent = true;
private boolean mStopSent = true;
Copy the code

In the activityStarted and activityResumed methods apply a ++ to both values and change the state of lifecycle

void activityStarted(a) {
    mStartedCounter++;
    if (mStartedCounter == 1 && mStopSent) {
        mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
        mStopSent = false;
 } } void activityResumed(a) {  mResumedCounter++;  if (mResumedCounter == 1) {  if (mPauseSent) {  mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);  mPauseSent = false;  } else {  mHandler.removeCallbacks(mDelayedPauseRunnable);  }  } } Copy the code

The activityPaused and activityStopped methods are used for these two values

void activityPaused(a) {
    mResumedCounter--;
    if (mResumedCounter == 0) {
        mHandler.postDelayed(mDelayedPauseRunnable, TIMEOUT_MS);
    }
} void activityStopped(a) {  mStartedCounter--;  dispatchStopIfNeeded(); } Copy the code

Here we see the delayed operation mentioned above

// Use handler to delay operations
mHandler.postDelayed(mDelayedPauseRunnable, TIMEOUT_MS);

// Delay 700 ms
static final long TIMEOUT_MS = 700; //mls
 private Runnable mDelayedPauseRunnable = new Runnable() {  @Override  public void run(a) {  // Distribute events as needed  dispatchPauseIfNeeded();  dispatchStopIfNeeded();  } };  void dispatchPauseIfNeeded(a) {  if (mResumedCounter == 0) {  mPauseSent = true;  mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);  } } void dispatchStopIfNeeded(a) {  if (mStartedCounter == 0 && mPauseSent) {  mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);  mStopSent = true;  } } Copy the code

Source code parsing to here, next we see how to use it

use

First, introduce the library

implementation "Androidx. Lifecycle: lifecycle - process: 2.3.0 - alpha05"
Copy the code

Since we are customizing the lifecycleObserver, we need to introduce it

implementation "Androidx. Lifecycle: lifecycle - common - java8:2.3.0 - alpha05"
Copy the code

Start by creating the ProcessLifecycleObserver class that implements the DefaultLifecycleObserver interface and prints the log in the corresponding lifecycle

Then add it to the custom Application

And that’s it!

demo

The Demo here

series

  • AndroidStudio nexus3. x builds Maven private server
  • What? There are over 200 lines of Gradle code in the project! You might need a Kotlin+buildSrc Plugin
  • Gradle relies on finding too much trouble? This plugin may help you
  • How to realize activity jump between components without using Router
  • New image loading library? Image loading library based on Kotlin coroutine — Coil
  • Use Navigation + Dynamic Feature Module to realize modularization
  • In addition to buildSrc, can you use this uniform configuration to rely on the version? Use opportunely includeBuild
  • Use kotlin extension functions and typealias to encapsulate LiveData with network state and resolve “sticky” events

About me

My name is Flywith24 and my blog content has been sorted here. Click on the Watch in the upper right corner to get updates of my posts 😉

  • The Denver nuggets

  • Jane’s book

  • Github