Activity-Hook填坑过程中温故而知新(2)

运行Demo,启动as自带模拟器 sdk28版本。进行跳转,

简单的跳转.gif
然后发现,生命周期函数并不执行。
image.png跳转过程中,只出现了onCreate onStart onResume, 照理说,跳转之后应该有 onPause onStop. 并且我回到这个Activity时,应该会有 onRestart onStart onResume, 但是也没有。

源码探索

为什么生命周期函数都不执行了?要找到这个原因,我必须先弄清楚一个问题: Activity的生命周期函数到底是由谁来调用的。

前期准备:

这里我不使用Demo工程,而是另外自己新建一个工程,写一个普通的startActivity跳转(这个我就不贴代码了). 因为我们要观察的是正常跳转

开工,进入源码(SDK 28 注意,app module的sdk也要28,必须用 androidStudio自带的AVD SDK 28模拟器才能 debug ):
(为了确保源码探索的完整流程,我们从 startActivity开始 . )

image.png
image.pngimage.png
这里产生2个分支,但是仔细观察之后,其实他们最终都走到了同一段逻辑:

Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, child,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, child.mEmbeddedID, requestCode,
ar.getResultCode(), ar.getResultData());
}

来解析这一段逻辑:

两句代码,一个是 mInstrumentation.execStartActivity
image.png

看来这一段并没有涉及到Activity生命周期函数的逻辑。
那么,看下一段:

mMainThread.sendActivityResult ,从 mInstrumentation.execStartActivity 执行之后,得到了一个ar,现在把这个ar 交给mMainThread(ActivityThread类的对象),于是,进入 ActivityThread源码:
image.png
这里的 scheduleTransaction方法,在ActivityThread的父类ClientTransactionHandler中:image.png
看到sendMessage,就怀疑,这里可能和Handler扯上关系了。
还记不记得 ActivityThread的父类ClientTransactionHandler scheduleTransaction()方法中 sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); 用到了 ActivityThread.H.EXECUTE_TRANSACTION. 我们在H extends Handler中找到这个switch case的分支:
image.png

一共就两句代码可能和Activity的生命周期函数调用有关,那么我有理由怀疑就是这一段代码在执行 生命周期函数. 那么 如何验证我的猜想是否成立? 答: debug源码(前面之所以要源码版本,AVD模拟器版本,项目版本gradle SDK版本都写成28,就是为了这里debug)
加上断点之后,开始debug,按下跳转按钮, 我们发现了惊人的现象:


一次跳转,我们debug发现了3个可能和生命周期函数有关的细节:
PauseActivityItem ,ResumeActivityItem,StopActivityItem,这3个是不是分别对应了 Activity的3个生命周期函数?
继续探索:
找到 TransactionExecutor类的execute()方法:
image.png

我们需要跟踪的是transaction参数 (因为这里只有一个参数…不跟踪它跟踪谁呢)
然而,这里,使用到这个参数的是两个方法,executeCallbacks()executeLifecycleState(),
而,在这两个方法中,我都找到了类似下面这样的代码:

final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);

推断出,生命周期函数一定和ActivityLifecycleItemexecute()postExecute()有关,还记不记得之前我们debug出来的PauseActivityItem ,ResumeActivityItem,StopActivityItem . 这3个类就是ActivityLifecycleItem的子类,进去看看:

image.png
debug 一下:
image.png
发现了ActivityThread,自然就联想到它的 H extends Handler ,ok, 就快接近真相了,表激动,暂且压制一下,我们还没有找到真凭实据。
又是一个抽象方法,直接找他的子类ActivityThread,
image.pngimage.pngimage.pngimage.png

终于接近真相了,这里已经很明显了,参数是Activity对象,并且执行了 activity.performPause().

image.png

真相大白,原来一个Activity的生命周期函数 onPause是这么调用的,绕了一大圈,最终我们重写的onPause()方法才被执行。

小结论

从我们startActivity开始,如果用一张图来展示 Activity生命周期函数如何被执行。无谓的绕绕绕去的省略中间环节,只展示重点环节,那就是这样。Activity生命周期函数追踪.jpg

解决方案

现在可以运行我的Demo工程,注意 请切换到 git时间点: 945df9, 按照上面的步骤去debug一下,结果发现,image.png
上一章节中图示的正常现象 PauseActivityItem ,ResumeActivityItem,StopActivityItem ,在这里并未看到,或者说,这里 EXECUTE_TRANSACTION 分支缺失了。肯定是因为我们hook的代码导致ActivityThreadH mH = new H()class H extends Handlervoid handleMessage(Message msg) 部分switch case 没有执行。

既然已经确定是 ActivityThread的 mH 有问题, 那么应该检查的,则是 hook mH的时候。

现在进入hook代码:image.pngimage.png回顾一下handler的责任链模式:image.png
按照我通常的hook思路,mH通常执行的是 第三级 成员函数handlerMessage(msg)的逻辑,我hook一下,给mH的成员变量mCallback赋值。 然后可以通过return 返回值来控制要不要继续执行 原handlerMessage(msg)的逻辑。如果mCallback.handlerMessage(msg)返回了true,那么就没有后续了,handlerMessage(msg)永远不会执行。如果是return false,handlerMessage(msg) 仍会执行。

已经很接近真凶了。我确定是mCallback.handlerMessage(msg)return true导致的问题。就检查一下我hook的时候,哪里return true了。Debug一下:

image.png这里list.size()是0,刚好这里return true了。
这里return一下,是因为源码中使用了list.get(0),我不能让它在list为0的情况下去get(0). 对,就是这么单纯,没有别的想法。

完美效果

行动吧,把 这里的return true 改为 return false。然后再 重新运行,观察日志,依然是从1跳转到2。
日志如下:


生命周期函数已经完整。问题解决!

可能隐患

问题解决,可喜可贺。当我兴高采烈地想在新买的华为mate30手机上试验效果时,发现。正常的Activity跳转和hook之后的跳转速度截然不同. 肉眼可见的速度差别,hook之后慢了不止一拍。其他手机尚未发现。也不知道是不是华为底层做了什么事情。总之,这又是下一阶段应该考虑的问题了。

结语

技术研究就是这样,问题是无止境的,优化是无止境的,一项技术的诞生,永远会伴随这无穷无尽的优化,重构,升级,增强,扩展。学习也是如此,所谓活到老学到老,技术人应该保持对技术的热情,执着和追求,坚持学习。像是今天Activity 生命周期函数是如何被调用的,以前只是疑惑,现在终于解开谜团,完完全全抽丝剥茧,得到真相.

所谓坑坑更健康,做技术不可以害怕坑坑洞洞,有坑,解决了坑,自己才能有收获。而且类似这种问题,我解决问题,就是将true改为false,花了1秒。但是我检查问题,找出真相的过程,花了1天。我相信工作中类似这种问题,不在少数。在没有足够了解核心代码逻辑的情况下,去编程,很有可能出一些细节性的小错误,这些错误往往是致命的。 所以,虽然SDK系统源码,一些第三方库源码,很大,很复杂,很多弯弯绕绕,各种回掉,各种映射,各种设计模式,看上去很可怕,但是我们没有退路,退缩不前只会让35岁被离职的风险加大。花点时间去补充基础知识的缺失,鼓起勇气去读源码,只要掌握正确的方法,也许能在源码的世界中找到一片不一样的天空

2019又一年过去了,与 各位技术人,共勉!

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

写在最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

链图片转存中…(img-TCaTVNJp-1712603256998)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值