【奇技淫巧】使用 ProcessLifecycle 优雅地监听应用前后台切换

前言

很快乐见到你,又来到了「奇技淫巧」系列,本系列介绍一些「骚操作」,或许不适合用于生产,但可以开拓思路

前些天在群里看到有人评论通过维护 activity 栈来监听程序前后台0 * C @切换的问题。其实单纯监听程序的前后台切换完全不需求维护 activity 栈,而现在比较干流的做4 i H =法是运用 registerActivityLifecycl| 9 2 SeCallbacks。而今天我来介绍一下运用 ProcessLifecycleOwner 来完结M a &这一功用

lifecycle-process 库

Android Jetpackm Q ` % 4 + Li& & y Z +fecycle 组件有一个可选库:lifecycle-process,它可认为整个 app 进程供给一个 P8 ) 9 processLifecyG v K | ~cleOwner

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换
ly V I P 3 i Xifecycle-pD ; y x P Vrocess 引入

该库十分简单,只要四个文件

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换
lifecycle-process

ProcessLifecycleOwnerInitializer 凭仗 ContentProvider 拿到 Context,用于初始化操作

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换
init

EmptyActivityLifecycleCallbac_ ^ [ b l SksApplication.ActivityLifecycleCallbacks 的完结类,内部为空完结

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换
EmptyActivityLifecycleCallbacks

Lifecycle9 n & q 4 : # Dispatcher 通过 ReportFragment 来 hook 宿主的生命周期工作

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换

中心逻辑都在 Pr2 9 S u # h W vocessLifecycleOwner 中

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换
ProcessLifecycleOwner

该类供给了整个 app 进程的 lifecycle

可以将其视为全部 activity 的 LifecycleOwner ,其中 Lifecycle.Event.ON_CREATE 只会分发一次,而 Lifecycle.Event.ON_DESTROY 则永远不会分发

其它的生命周X R 期工作将按以下规则分发:

ProcessLifecycleOwner 会分发 Lifecycle.Eve5 V I Ont.ON_START 和 Lifecycle.Event.ON_RESUb 8 z oME 工作(在第一个 activity 移动到这些工作时)

Lifecycle.Event.ON_PAUi & M ] T .SE 与 Lifecycle.Event.ON_STOP 会在最后一个 activity 移动到这些情况后 推延1 8 H # M a {发,O # 2 ^ .该推延满足长,以保证由于装备更改等操作重建 activity 后不会分发任何工作

对于监听运用在前后台切换且不需求毫秒级的精度的场景,这十分有用

ProcessLifecycleOwner 源码解析

依据上图我们得知 ProcessLifecycleOwn @ { 1 =ner 完结了 LifecycleOwner 接口

由于在 ProcessLifecycleOwnerInitializee o Xr 中初始化时传入了 Context,因而 ProcessLifecycleOwner 在 attach 方法中凭仗 Context 拿到了 Application 实例,并调用了 registerActivityLiJ P hfecycleCallbacks

void attach(Contey x 0 % y x I dxt context) {
    mHandler = new Handler();
    mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    Application app = (Application) context.getA4 u : upplicationContext();
    app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks()
        @RequiresApi(29)
        @Override
        public void onAF / ] 1 o f y G }ctivityPreCreated(@NonNull Activity acti- ^ q T G ;vity,
                @Nullable Bundle savedIT 5 5 p + ( + + enstanceState) {
            //我们需求 ProcessLifecycleOwner 刚好在第一个 activity 的 Li[ r + 2 Y A 7 ifecycleOwnB n P B * W p qer started/resumed 之前获取 ON_START 和 ON_RESUME。
            //ac0 : N w 4 q B b Ytivity 的 LifecycleOwner 通过在 onCreate() 中添加 activity 注册的 callback] V m L & = 0 i Y 来获取 started/resumed 情况。
            //通过在 onActiv! ? _ k # !ityPreCreated() 中添加我们自己的 activity 注册的 callback,我们首要获得了回调,一同与 Activity 的 onStart()/ onResume()回调比较仍具有正确的相对次第

            activity4 / G t N R u.registerActivityLifecycleCallbacks(new EmptyActivityLifecycl
                @Override
                public void onActivityPostStarted(@NonNull Activity activity) {
                    activit| u V K s n LyStarted();
                }
                @Override
                public void onActivityPostResumed(@NonNull Activity activity) {
                    activityResumed();
                }
            });
        }
        @Override
        public void onActivityCreated(Activity activity, Bund. M V } a $ Rle savedIn q 4 , / p T %stanceStat
            //仅在API 29 之前运用 ReportFragment,在此之后,我们可以运用# R V g ! N %在 onActivityPreCreated() 中注册的 onActivityPostStarted 和 onActivityPostResumed 回调
            if (BuilZ M Q N t Bd.VERSION.SDK_INT < 29) {
                ReportFragment.get(activity).setProcessListener(mInitializationLi
            }
        }
        @OY u l # 3 , ^ E @verrid[ ; P e De
        public void onActivityPausn y ped(Activity activity) {
            activityPaused();
        }
        @Override
        public void onActivityStox r c J f ? 8 9 ,pped(Activity activity) {
            activityStopped();
        }
    });
}

内部维护了 Started 和 Resumed 的数量

private int mStartedCounter = 0;
private int mResumedCounter = 0;
private boolean mPauseSent = true;
private boolean mStopSent = true;

并在 activityStarted 和 activityResumed 方法中对 这两个数值进行 ++,并更改 lC Z 8 ? { v u zifecycle 情况

void activityStarted() {
    mStQ Z ;artedCounter++;
    if (mStartedCounter == 1 && mStopSent) {
        mRegistry.handleLifecyZ @ } , fcleEvent(Lifecycle.Event.ON_O = 9 k L ( ~START);
        mStopSy ^ M [ yent = false;
    }
}
void activityR( A ! +esumz W n h F $ Q Eed() {
    mResumedCounter++;
    if (mResumedCounter~ X h = == 1) {
        if (mPauseSent) {
            mRegistry.T W ) handleLifecycl` v y r 8 n x 3 WeEvent(Lifecycle.Eventy e { K , [.ON_RESUME);
            m6 ] F ZPauseSent = false;
        } else {
            mHane 7 o Bdler.removeCallbacks(mDelayedPauseRunnable);
        }
    }
}

在 activityPaused 和 activityStopped 方法对这两个数值进行 —

void activityPaused() {
    mResumedCounter--;
    if (mResumedCg P i C / T { r &ounter == 0) {
        mHandler.postDelayed(mDelayH b 4 ? Y 5 9edPauseRunnable, TIMEOUT_MS);
    }
}
void activityStopped() {
    mStartedCounter--;
    dispatchStopIfNeeded();
}

而在这儿我们看到了上文说到的推延操作

// 运用 handler 进行推延操作
mHandU B T M :ler.postDelayed(mDela8 j O 0 iyedPauseRunnable, TIMEOUT_MS);

// 推延 700 ms
static final lS 7 ] $ @ong TIMEOUT_MS = 700; //mls

private Ruo E + ^nnable mDelayedPauseRunnable = new Runnable() {
    @Override
    public void run() {
        // 依据需求分发工作
        dispatchPauseIfNeede; e 9 ` e $d();
        dispatchSt- = I )opIfNeeded();
    }
};

void disp* s $ k (atchPauseIfNeeded() {
    if (mResumedCounter == 0) {
        mPauseSent = trueQ o Y x ] 4;
        mRegistry.handleLifecI j ` . ;ycleEvent(Lifecycle.Event.{ J w B R S 3 / RON_PAU? L 1 BSEW u w }  g ] H);
    }
}
void dispatchStopIP x `fNeeded() {
    if (mStartedCounter == 0 && mPauseSent) {
        mRegistry.handleLifecycleEvent(Lifec4 G Dycle.Event.ON_STOP);
        mStopSent = true;
    }
}

源码就解析到这儿,接下来咱x I {们看看怎样运用吧

运用

首要引入该库

implementation "androidx.lifecycle:lifecycle-process:2.3.0-a _ B t ialpha05"7 4 3 P c R /

由于我们要自定义 lifec4 f T = , QycleObserver,因而还需引入

implementation "androidx.lifecycle:lifecyc8 M C U 3 % 0le-common-java8:2.Y * l a 3 $ : !3.0-alphI t s I u A T i (a05"

首要创立 ProcessLifecycleObserver 类,完结 DefaultLifecycleObserver 接口,在相应的生命周期中打印 log

接着在自定义 Ap= 2 x P .plicatiq Z i p b J i mon 中参加

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换

这样便完结] ^ 6 { . w了!

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换
演示k k o O o z * i e

Demo 在这儿

系列文章

  • 【奇技淫巧】AndroidStudi~ C 8 uo Nea h j X dxus3n p I – N j.x 建立 Maven 私服遇到问题及处理计划
  • 【奇技淫巧】什么?项目里 gradle 代码超越 200 行了!g m ) U ? 6 f你或许需求 Kotlin+buildSrc Plugin
  • 【奇技淫巧】gradle 依托查找太麻烦?这个插件或许帮到你
  • 【奇技淫巧】Android 组件化不运用 Router 怎样完结组件间 activity 跳转
  • 【奇技淫巧】新的图片加载库?依据 Kotlin 协程的图片加载库——Cox G L G ^ E ? u *il
  • 【奇技淫巧】运用 Navigation + Dynamic Feature Module 完结模– l + , E块化
  • 【奇技淫巧】除了 bj x suildSrc 还能这样共同装备依托版本?巧用 includeBuild
  • 【奇技淫巧】巧用 kotlin 扩展函数和 typealias 封装 带网络情况和处理「粘性」工作的 LiveData

关于我

我是 Flywith24,我Z b b的博客内容现已分类整理 在这儿,点击右上角的 Watch 可以及时获取0 _ 6 b z s C e我的文章更新哦

  • 掘金

  • 简书

  • Github

【奇技淫巧】运用 ProcessLifecycle 高雅地监听运用前后台切换