高效获知Activity的生命周期

文章介绍了如何通过继承Instrumentation并重写其生命周期方法来全局监听Android应用中Activity的生命周期,包括onCreate、onStart、onResume等关键状态。这种方法的优点是全局监听且对性能影响小,但缺点是无法直接应用于Fragment的生命周期监听。实现过程涉及反射替换ActivityThread中的Instrumentation实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Activity生命周期监听

使用 Instrumentation 对 Activity 生命周期进行监听。
优点:

  • 全局仅一次反射,性能影响极小
  • 所有Activity的生命周期都能够被监听到
  • 由于Java的单继承,为了拓展性,可以使用装饰器模式对Instrumentation进行功能加强,但个人觉得这样做不推荐

缺点:

  • 只使用于Activity的生命周期监听
  • FragmentManger实例的应用关系复杂,不容易反射替代(应该可以实现,或者用其他方式Hook)

1. 实现原理:

回顾到 Activity 的启动流程,AMS 向 APP 进程发来 Activity 启动请求,ApplicaitonThread 作为binder线程的维护者收到消息,将消息回调到 ActivityThread 的Handler.handleMessage(),启动Activity。核心为:performLaunchActivity()->Instrumentation.callActivityOnCreate()->activity.performCreate()
类似的,还有:

//Instrumentation.java
pubilc void callActivityOnCreate(Activity activity,Bundle budle,PsersistableBundle p){
//...
}
public void callActivityOnCreate(Activity activity,Bundle 
bundle){
//...
}
public void callActivityOnStart(Activity activity){
//...
}
//...OnPause、OnStop、OnDestroy也都类似

这些方法都是开放的,所有Activity的生命周期都会经过它,而且这些方法都明确了要调用哪个Activity的生命周期。这就给了我们一个机会来监听 Activity。同时这个设计也表现了 Android 的事件驱动设计。

2. 实现方法

我们可以通过继承一个 Instrumentation 来给这些方法加个钩子,注意一定要回调父类的本方法,否则就破坏程序了:


public class FyInstrumentation extends Instrumentation {

    public static final String TAG = "FyInstrumentation";

    //------------   onCreate   ------------
    @Override
    public void callActivityOnCreate(Activity activity, Bundle bundle) {
        Log.e(TAG, "begin onCreate: " + activity);
        super.callActivityOnCreate(activity, bundle);
        Log.e(TAG, "end onCreate" + activity);
    }

    @Override
    public void callActivityOnCreate(Activity activity, Bundle bundle, PersistableBundle persistentState) {
        Log.e(TAG, "begin onCreate: " + activity);
        super.callActivityOnCreate(activity, bundle,persistentState);
        Log.e(TAG, "end onCreate" + activity);
    }

    //--------------  onStart ---------------
    @Override
    public void callActivityOnStart(Activity activity){
        Log.e(TAG, "begin onStart: " + activity);
        super.callActivityOnStart(activity);
        Log.e(TAG, "end onStart" + activity);
    }

    //--------------  onResume ---------------
    @Override
    public void callActivityOnResume(Activity activity){
        Log.e(TAG, "begin onResume: " + activity);
        super.callActivityOnResume(activity);
        Log.e(TAG, "end onResume" + activity);
    }

    //--------------  onPause ---------------
    @Override
    public void callActivityOnPause(Activity activity){
        Log.e(TAG, "begin onPause: " + activity);
        super.callActivityOnPause(activity);
        Log.e(TAG, "end onPause" + activity);
    }

    //--------------  onStop ---------------
    @Override
    public void callActivityOnStop(Activity activity){
        Log.e(TAG, "begin onStop: " + activity);
        super.callActivityOnStop(activity);
        Log.e(TAG, "end onStop" + activity);
    }

    //--------------  onDestroy ---------------
    @Override
    public void callActivityOnDestroy(Activity activity){
        Log.e(TAG, "begin onDestroy: " + activity);
        super.callActivityOnResume(activity);
        Log.e(TAG, "end onDestroy" + activity);
    }


}

把我们的 FyInstrumentation 替换掉原有的 Instrumentation。
何时替换都可以,只需要在我们目标监听的 Activity 开始之前就替换好即可。所以我这里就把它放在 MyApplication 中,在所有 Activity 开始之前就替换好。
先写一个工具类,由于单例设计,ActivityThread实例的获取,我们可以通过静态方法currentActivityThread()来获取。再对它的成员变量 mInstrumentation 进行反射替换成我们的 Instrumentation。



public class HookHelper {

    public static final String TAG= "HookHelper";

    public static void attachContext() throws Exception{
        //获取到当前的activityThread
        Class<?> atClazz = Class.forName("android.app.ActivityThread");
        Method method = atClazz.getMethod("currentActivityThread");

        Object at = method.invoke(null);
        Log.e(TAG,at.getClass().getName()+"  ");
        Field f = at.getClass().getDeclaredField("mInstrumentation");
        f.setAccessible(true);
        f.set(at,new FyInstrumentation());
    }
}

最后,我们在MyApplication中进行替换:


public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        try {
            HookHelper.attachContext();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.测试监听:

进入到 MainActivity,然后点击按钮跳转到TestFragmentActivity:

2023-02-20 15:48:37.280 3737-3737/com.company.rxjavastudy E/FyInstrumentation: begin onCreate: com.company.lifecycle2.MainActivity@d3e13d
2023-02-20 15:48:37.700 3737-3737/com.company.rxjavastudy E/FyInstrumentation: end onCreatecom.company.lifecycle2.MainActivity@d3e13d
2023-02-20 15:48:37.703 3737-3737/com.company.rxjavastudy E/FyInstrumentation: begin onStart: 
...
2023-02-20 15:52:39.380 3737-3737/com.company.rxjavastudy E/FyInstrumentation: end onStopcom.company.lifecycle2.MainActivity@d3e13d

内容太多了,我把顺序梳理如下:APP开启后进入到活动A,点击按钮跳转到活动B:

A-onCreate
A-onStart
A-onResume
A-onPause
B-onCreate
B-onStart
B-onResume
A-onStop

测试完成,监听成功。
对生命周期的细节,大家可以复习关于:Activity的四大启动模式与Activity跳转的生命周期的关系,也注意一下 onNewIntent(),这是在复用Activity的时候调用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值