高效获知Activity的生命周期
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 ------------@Overridepublic void callActivityOnCreate(Activity activity, Bundle bundle) {Log.e(TAG, "begin onCreate: " + activity);super.callActivityOnCreate(activity, bundle);Log.e(TAG, "end onCreate" + activity);}@Overridepublic 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 ---------------@Overridepublic void callActivityOnStart(Activity activity){Log.e(TAG, "begin onStart: " + activity);super.callActivityOnStart(activity);Log.e(TAG, "end onStart" + activity);}//-------------- onResume ---------------@Overridepublic void callActivityOnResume(Activity activity){Log.e(TAG, "begin onResume: " + activity);super.callActivityOnResume(activity);Log.e(TAG, "end onResume" + activity);}//-------------- onPause ---------------@Overridepublic void callActivityOnPause(Activity activity){Log.e(TAG, "begin onPause: " + activity);super.callActivityOnPause(activity);Log.e(TAG, "end onPause" + activity);}//-------------- onStop ---------------@Overridepublic void callActivityOnStop(Activity activity){Log.e(TAG, "begin onStop: " + activity);super.callActivityOnStop(activity);Log.e(TAG, "end onStop" + activity);}//-------------- onDestroy ---------------@Overridepublic 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{//获取到当前的activityThreadClass<?> 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 {@Overridepublic 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的时候调用的。
相关文章:
高效获知Activity的生命周期
Activity生命周期监听 使用 Instrumentation 对 Activity 生命周期进行监听。 优点: 全局仅一次反射,性能影响极小所有Activity的生命周期都能够被监听到由于Java的单继承,为了拓展性,可以使用装饰器模式对Instrumentation进行功…...

分析现货黄金价格一般有什么方法
分析现货黄金价格一般有什么方法呢?我相信很多投资者都会说,是技术分析。很多人并不知道技术分析是什么,并且技术分析是如何去分析现货黄金价格的,那么本文就介绍一下技术分析的主要分类。可以说,小编的其他文章都是以…...

Spring中的拦截器
这里写目录标题基本概念HandlerInterceptor拦截器HandlerInterceptor讲解MethodInterceptor拦截器二者的区别基本概念 在web开发中,拦截器是经常用到的功能。它可以帮我们预先设置数据以及统计方法的执行效率等等。 Spring中拦截器主要分两种,一个是Han…...
【Linux操作系统】【综合实验四 Linux的编译环境及线程编程】
文章目录一、实验目的二、实验要求三、实验内容四、实验报告要求一、实验目的 要求熟悉Linux环境中的程序编译、调试与项目管理过程并能实现具体操作;熟练使用基础函数库中与线程库中的管理函数,实现用户线程编程过程,并深入了解Linux的线程…...
Switch 如何使用NSCB 转换XCI NSP NSZ教程
很多小白经常碰到Switch游戏文件格式和预期不符的情况,比如碰到nsz自己不会安装(安装NSZ格式文件教程);或者是碰到xci格式的,想转换为nsp;抑或想将nsz格式文件还原回nsp格式。本文对此提供了解决方案。 文中…...

JVM12 字节码指令集
1. 概述 2. 加载与存储指令 2.1. 局部变量压栈指令 iload 从局部变量中装载int类型值 lload 从局部变量中装载long类型值 fload 从局部变量中装载float类型值 dload 从局部变量中装载double类型值 aload 从局部变量中装载引用类型值(refernce) iload_0 从…...
centos之python安装与多版本python之间的共存
一、背景 随着python版本迭代加快,有写python模块再低版本无法运行,此时需要我们在进行安装一个python版本 例如:uvloop 在python3.7上运行;python 3.6官方不再维护与更新 有些模块或不支持较低版本、有些模块支持较高版本python…...
SpringBoot学习笔记(一)
Idea中隐藏指定文件或指定类型文件 setting->File Types->Ignored Files and Folders输入要隐藏的文件名,支持*号通配符回车确认添加 SpringBoot概述 parent 小结: 开发SpringBoot程序要继承spring-boot-starter-parentspring-boot-starter-pa…...

美国原装KEYSIGHT E4981A(安捷伦) E4981A电容计
KEYSIGHT E4981A(安捷伦) Keysight E4981A(安捷伦)电容计为生产线中的陶瓷电容器测试提供了高速、可靠的测量。E4981A 实现了电容从小到大的测量能力,测量准确。Agilent E4981A 电容计有助于提高测试吞吐量࿰…...

K8S的基础概念
目录 一、k8s概述 1、k8s简介 1.1 k8s的作用 1.2 k8s的由来 1.3 k8s的含义 1.4 k8s的官网 1.5 GitHub 2、为什么要用 K8S? 2.1 K8s的目标 2.2 K8s解决了裸跑Docker 的若干痛点: 2.3 K8s的主要功能 3、K8s的特性 二、Kubernetes 集群架构与组件 1、工作流程 2、…...

【数据结构】——环形队列
文章目录一.环形队列的定义及其特点二.使用数组来实现环形队列1.创建一个队列2.初始化队列3. 判断环形队列是否为空4.判断环形队列是否已满5. 向循环队列插入元素,插入成功返回真6.删除环形链表的数据7. 取队头元素8.取队尾元素8.释放空间总结一.环形队列的定义及其…...

windows 安装Qt
下载 下载地址https://download.qt.io/,此文已5.7.0为例子。 根据图片依次选择即可。 安装 安装过程参考另一篇文章Ubuntu 安装 Qt5.7.0即可 配置环境变量 ps:我就是之前没配置环境变量,直接使用创建项目,项目源码直接运行是…...

spring cloud gateway集成sentinel并扩展支持restful api进行url粒度的流量治理
sentinel集成网关支持restful接口进行url粒度的流量治理前言使用网关进行总体流量治理(sentinel版本:1.8.6)1、cloud gateway添加依赖:2、sentinel配置3、网关类型项目配置4、通过zk事件监听刷新上报api分组信息1、非网关项目上报api分组信息…...

wafw00f工具
wafw00f Web应用程序防火墙指纹识别工具 github地址:https://github.com/EnableSecurity/wafw00f 安装环境:python3环境 —>使用 pip install wafw00f 进行安装 安装成功后目录:python安装目录中的Lib\site-packages\wafw00f 本机为&a…...

论文阅读笔记-DiffusionInst: Diffusion Model for Instance Segmentation
文章目录DiffusionInst: Diffusion Model for Instance Segmentation摘要介绍任务介绍实例分割的几种方法想法来源贡献方法整体结构Mask RepresentationDiffusionInst组成TrainingInference不足之处感悟DiffusionInst: Diffusion Model for Instance Segmentation 代码&#x…...

解决CondaUpgradeError网上的方法都不奏效(回退版本、upgrade/update都不行)的问题和CondaValueError
问题描述 Executing transaction: failed ERROR conda.core.link:_execute(502): An error occurred while installing package ‘conda-forge::certifi-2022.9.24-pyhd8ed1ab_0’. CondaUpgradeError: This environment has previously been operated on by a conda version…...

基于某业务单登陆场景并发测试实战
文章目录1 测试目的2 测试目标和测试对象3 名词解释4 测试说明5 测试环境和工具5.1 测试工具5.2 测试环境5.3 人力计划6 测试用例6.1 方案设计6.2 接口地址6.3 接口参数6.3.1 header参数6.3.2 请求参数7 脚本设计8 监控数据8.1 虚拟用户并发情况8.2 事务响应时间8.3 每秒点击次…...

JVM内存模型
程序计数器 多线程时,当线程数超过CPU数量或CPU内核数量,线程之间就要根据时间片轮询抢夺CPU时间资源。因此每个线程有要有一个独立的程序计数器,记录下一条要运行的指令。线程私有的内存区域。如果执行的是JAVA方法,计数器记录正…...

三、NetworkX工具包实战3——特征工程【CS224W】(Datawhale组队学习)
开源内容:https://github.com/TommyZihao/zihao_course/tree/main/CS224W 子豪兄B 站视频:https://space.bilibili.com/1900783/channel/collectiondetail?sid915098 斯坦福官方课程主页:https://web.stanford.edu/class/cs224w NetworkX…...

分布式之Raft共识算法分析
写在前面 在分布式之Paxos共识算法分析 一文中我们分析了paxos算法,知道了其包括basic paxos和multi paxos,并了解了multi paxos只是一种分布式共识算法的思想,而非具体算法,但可根据其设计具体的算法,本文就一起来看…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...