Android Studio 的一个主要目标是为你的 app 提供快速的代码编辑和验证工具。当我们创建 Instant Run 的时候,我们希望它能够明显加速你的开发流程,但是现在看来它并没有达到预期目标。作为 Project Marble 的一部分,我们一直在重新思考 Instant Run,并提出了一个更实用的替代方案 Apply Changes。Apply Changes 作为一个可以加快开发流程的新方法,最初在 Android Studio 3.5 的 Canary Channel 发布预览。在这篇文章中,我们想深入聊聊它是如何工作的,以及迄今为止我们的工作。
Instant Run
通过 Instant Run,我们想解决两个问题:1)节省构建和部署应用程序到设备上的时间,2)使应用程序在不丢失运行状态的情况下部署更改。为了在 Instant Run 中做到这一点,我们在构建的时候重写你的 APK 来注入钩子,以便在运行的时候进行类的替换。要更详细的了解 Instant Run 背后的架构,可以参考几年前 Medium 上的这篇文章。
对于简单的 app,这个方案一般都表现很好,但是对于更复杂的 app 来说,它可能会使构建时间变长,或者会由于 app 与 Instant Run 构建过程之间有冲突而导致令人头疼的错误。随着这些问题的出现,我们在后续的版本中持续改进提升 Instant Run。但是,我们无法完全解决这些问题,让它符合我们的期望。
我们后退了一步,决定从头开始构建一个新的架构,它就是 Apply Changes。和 Instant Run 不同,Apply Changes 不会在构建的时候修改你的 APK。取而代之,我们用 Android 8.0(Oreo)上支持的 Runtime Instrumentation 以及更新的设备和模拟器在运行时重定义类。
Apply Changes
对于运行在 Android 8.0 或者更新版本上的设备和虚拟机,Android Studio 现在有三个按钮来控制应用程序重启的程度:
-
Run 会部署所有的改动并重启应用程序。
-
Apply Changes 会尝试应用资源和代码的更改,并只重启 Activity 而不是重启应用程序。
-
Apply Code Changes 会尝试应用代码的更改,而不重启任何东西。
通常只有方法体内部的代码更改才对 Apply Changes 具有兼容性。
原则
基于在 Instant Run 上的经验和反馈,我们采用了一些原则来指导我们的架构设计和决策:
-
将构建/部署的速度和状态丢失两者独立开。我们想将节省构建和部署的时间,与在不丢失运行状态的情况下部署更改这两个目标分开。不管是一般的运行或者调试,或者代码的热替换,快速构建和部署应该是所有部署类型的目标。作为构建 Apply Changes 的一部分,我们发现了很多可以优化构建和部署速度的领域,在后面的文章中,我们会详细介绍它们。
-
稳定性至关重要。即便在 100 次中这个功能以极快的速度运行了 99 次,如果你的 app 因为这个功能而崩溃了一次,并且你花半个小时来尝试找出原因,那么其他 99 次获得的收益也就全部被抵消了。由于我们坚持这一原则,Apply Changes 不会像 Instant Run 那样在构建期间修改你的 APK。带来的副作用是,在我们进行稳定性优化的早期版本中,Apply Changes 会比 Instant Run 的平均速度稍慢,但是我们将继续提高构建和部署的速度。
-
透明。Instant Run 按钮会自动决定是否在必要时重启你的 app 或者 Activity,对于这样不可预测性和行为不一致性的反馈,我们也考虑了进来。我们希望在任何时候你都能清楚透明的了解 Apply Changes 要做什么,如果你的代码有不兼容的修改会发生什么。因此如果有检测到与 Apply Changes 不兼容的修改,我们现在会明确提示你。
架构
我们来深入研究下 Apply Changes 是如何工作的。在你修改 app 之后,当前设备上已经安装或正在运行的应用程序和 Android Studio 刚刚编译出来的应用程序是有差异的,Apply Changes 需要弄清楚如何应用这些差异。这个过程可以分成两个步骤:1)弄清楚差异是什么,2)将差异发送到设备上并应用它。
为了快速确定差异,Apply Changes 没有从设备抓取完整的 APK,而是向设备发送一个快速的请求,去拉取已经安装 APK 的对应目录#Central_directory_file_header)和签名。将这两部分信息和新 APK 进行比较,Apply Changes 可以高效地找出自上次部署以来修改过的文件列表,而不需要检查 APK 的所有内容。需要注意的是,这个算法并不依赖于构建系统,因为差异并不是与上一次构建相比较得到的,而是与安装到设备上的 APK 比较得来。由于 Apply Changes 只针对 APK 之间的差异进行操作,因此它并不要求 Gradle 插件版本和 Gradle 同步。这样,Apply Changes 可以运行于所有的构建系统上。
在生成更改过的文件列表之后,根据所更改的内容,需要执行不同的操作来将这些更改应用到正在运行的 app 上,这也决定了要使这些更改生效,app 需要重启到什么程度:
更改 resource/asset 文件。 这种情况下会重新安装应用程序,但只会重启 Activity,并获取修改后的资源。只有修改过的资源才会被发送到设备上。
更改 .dex 文件。 Android 8.0 的 Android Runtime 提供了替换已加载类的字节码的能力,只要新的字节码不会改变内存中现有对象的布局。这意味着要想兼容 Apply Changes,更改的代码会有一些限制:方法名,类名,和签名都不能更改,它们的成员变量也不能更改。
但这个机制不能在 .dex 级别,只能在类级别工作。否则,如果 .dex 文件包含成千上万个类,即便只有一个类更改了,也需要对所有类进行替换,这样效率太低。对于 .dex 文件,我们比较它的内容来找出更改过的类,只替换掉它们。如果替换成功(例如,类的布局没有改变),为了避免正在运行和已安装的 app 的版本不一致,会在后台安装 app。
更改 .dex 文件和资源文件。 这个情况是上面两种情况的组合。先处理代码的部分,如果成功了,会和新的资源一起安装。为了加载新的资源,主 Activity 会被重启。这是一个全做或全不做的操作,如果代码的改变不能成功地应用,正在运行的 app 什么都不会改变。
更改其他东西。 这是最糟的情况,比如 AndroidManifest.xml 或者 native .so 这些文件被更改了。在这种情况下,是不可能不重启应用程序来应用更改的。“Apply Changes” 和 “Apply Code Changes”这两个操作都不会试图去部署它,它们会告诉用户应用程序需要重启。
关于架构的更多详细信息,请收听 Android Developers Backstage 播客的最新一集,技术负责人 Esteban de la Canal 对 Apply Changes 进行了深入探讨。
比较 .dex 文件
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
面试复习笔记:
这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《960页Android开发笔记》
《1307页Android开发面试宝典》
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!**