Android Studio的Instant Run工作原理及用法

zwwko 8年前
   <h2>前言</h2>    <p>看到一篇介绍Instant Run的文章,觉得蛮不错的,翻译记录一下,其中夹杂着自己的理解(<a href="/misc/goto?guid=4959672631128419622">原文地址</a>),最后附上Install Run的使用方法。(本文图片<a href="/misc/goto?guid=4959672631128419622">出处</a>)<br> <em>tips:文中所有链接地址都国内或许不能访问</em></p>    <h2>Instant Run</h2>    <p>Instant Run,是android studio2.0新增的一个运行机制,在你编码开发、测试或debug的时候,它都能显著减少你对当前应用的构建和部署的时间。<br> 当我们第一次点击run、debug按钮的时候,它运行时间和我们往常一样。但是接下去的时间里,你每次修改代码后点击run、debug按钮,对应的改变将迅速的部署到你正在运行的程序上,传说速度快到你都来不及把注意力集中到手机屏幕上,它就已经做好相应的更改。</p>    <h3>一个典型的构建周期流程图</h3>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fe997a72d71c1d847dd38b7262b70f90.png" alt="Android Studio的Instant Run工作原理及用法" width="691" height="328"></p>    <p style="text-align:center">构建->部署->安装->app登录->activity创建</p>    <blockquote>     <p>instant run的目标:尽可能多的剔除不必要的步骤,然后提升必要步骤的速度。</p>    </blockquote>    <p>在实践中,这意味着:</p>    <ul>     <li>只对代码改变部分做构建和部署</li>     <li>不重新安装应用</li>     <li>不重启应用</li>     <li>不重启activity</li>    </ul>    <h2>热拔插,温拔插,冷拔插</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3e11513853f61ec95f0d29eb21d7c0de.png" alt="Android Studio的Instant Run工作原理及用法" width="700" height="280"></p>    <p style="text-align:center">instant run = 增量构建 + 热 或 温 或 冷拔插</p>    <p><br> <strong>热拔插</strong>:代码改变被应用、投射到APP上,不需要重启应用,不需要重建当前activity。<br> 场景:适用于多数的简单改变(包括一些方法实现的修改,或者变量值修改)<br> <strong>温拔插</strong>:activity需要被重启才能看到所需更改。<br> 场景:典型的情况是代码修改涉及到了资源文件,即resources。<br> <strong>冷拔插</strong>:app需要被重启(但是仍然不需要重新安装)<br> 场景:任何涉及结构性变化的,比如:修改了继承规则、修改了方法签名等。</p>    <h2>Instant Run运行原理</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/416424dea42576bf5e96c3a9572390e6.png" alt="Android Studio的Instant Run工作原理及用法" width="699" height="423"></p>    <p style="text-align:center">Manifest整合,然后跟res、dex.file一起被合并到APK</p>    <p><br> manifest文件合并、打包,和res一起被AAPT合并到APK中,同样项目代码被编译成字节码,然后转换成.dex 文件,也被合并到APK中。</p>    <h2>首次运行Instant Run,Gradle执行的操作</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5dd6a61fa5fd85244ef6ceaee8507133.png" alt="Android Studio的Instant Run工作原理及用法" width="696" height="417"></p>    <p style="text-align:center">APK生成流程</p>    <p>在有Instant Run的环境下:一个新的App Server类会被注入到App中,与Bytecode instrumentation协同监控代码的变化。<br> 同时会有一个新的Application类,它注入了一个自定义类加载器(Class Loader),同时该Application类会启动我们所需的新注入的App Server。于是,Manifest会被修改来确保我们的应用能使用这个新的Application类。(这里不必担心自己继承定义了Application类,Instant Run添加的这个新Application类会代理我们自定义的Application类)<br> 至此,Instant Run已经可以跑起来了,在我们使用的时候,它会通过决策,合理运用冷温热拔插来协助我们大量地缩短构建程序的时间。</p>    <blockquote>     <p>在Instant Run运行之前,Android Studio会检查是否能连接到App Server中。并且确保这个App Server是Android Studio所需要的。这同样能确保该应用正处在前台,因为目前是不支持多台设备多程序同时执行。</p>    </blockquote>    <h2>热拔插</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5f40d29e3536f83263acba6d2a5f6620.png" alt="Android Studio的Instant Run工作原理及用法" width="417" height="331"></p>    <p style="text-align:center">App Server</p>    <p><br> Android Studio monitors: 运行着Gradle任务来生成增量.dex文件(这个dex文件是对应着开发中的修改类) Android Studio会提取这些.dex文件发送到App Server,然后部署到App。<br> 因为原来版本的类都装载在运行中的程序了,Gradle会翻译,更新好这些.dex文件(Gradle修改class的原理,请戳<a href="/misc/goto?guid=4959672631233310996">链接</a>),发送到App Server的时候,交给自定义的类加载器来加载.dex文件。看看下面原理图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/028c83b483135efe5bdebf2554edfa96.png" alt="Android Studio的Instant Run工作原理及用法" width="404" height="321"></p>    <p style="text-align:center">App Server</p>    <p><br> App Server会不断监听是否需要重写类文件,如果需要,任务会被立马执行。新的更改便能立即被响应。我们可以通过打断点调试来发现它确实是这么做,操作如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/ec639baae8cb1422aa88f887dee6fed0.gif" alt="Android Studio的Instant Run工作原理及用法" width="800" height="450"></p>    <p style="text-align:center">实际效果</p>    <h2>温拔插</h2>    <p>温拔插需要重启Activity,因为资源文件是在Activity创建时加载,所以必须重启Activity来重载资源文件。<br> 目前来说,任何资源文件的修改都会导致重新打包再发送到APP。但是,google的开发团队正在致力于开发一个增量包,这个增量包只会包装修改过的资源文件并能部署到当前APP上。</p>    <blockquote>     <p><strong>注意</strong>:温拔插涉及到的资源文件修改,在manifest上是无效的(这里的无效是指不会启动Instant Run),因为,manifest的值是在APK安装的时候被读取,所以想要manifest下资源的修改生效,还需要触发一个完整的应用构建和部署。总结起来:如果你修改了manifest相关的资源文件,还是需要面临和以前一样的龟速构建。</p>    </blockquote>    <p>所以温拔插实际上只能应对少数的情况,它并不能应付应用在架构、结构上的变化。例如:annotations,fields的增删改、父类文件的修改、static修饰的类、方法、常量等的修改都只能依靠冷拔插。</p>    <h2>冷拔插</h2>    <p>应用部署的时候,会把工程拆分成十个部分,每部分都拥有自己的.dex文件,然后所有的类会根据包名被分配给相应的.dex文件。当冷拔插开启时,修改过的类所对应的.dex文件,会重组生成新的.dex文件,然后再部署到设备上。<br> 之所以能这么做,是依赖于Android的ART模式,它能允许加载多个.dex文件。ART模式在android4.4(API-19)中加入,但是Dalvik依然是首选,到了android5.0(API-21),ART模式才成为系统默认首选,所以Instant Run只能运行在API-21及其以上版本,至于低版本的话,会重新构建整个应用(下文会提及低版本解决思路)</p>    <h2>Instant Run是不能回退的</h2>    <p>代码更改可以通过热拔插快速部署,但是热拔插会影响应用的初始化,所以我们不得不通过重启应用来响应这些修改。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4b43720a8f7c7243c7ddd81c23aaa5cd.gif" alt="Android Studio的Instant Run工作原理及用法" width="800" height="450"></p>    <p style="text-align:center">展示增量构建,重启APP,然后回退(这里回退不了,数据还是4)</p>    <h2>Instant Run 技巧与提示</h2>    <p>Instant Run是被Android Studio控制的。所以我们只能通过IDE来启动它,如果通过设备来启动应用,Instant Run会出现异常情况。</p>    <blockquote>     <p>更多的技巧,请点<a href="/misc/goto?guid=4959672631313142644">这里</a>,然而多数是没什么用,不需要记住的。</p>    </blockquote>    <ul>     <li>如果应用的minSdkVersion小于21,可能多数的Instant Run功能会挂掉,这里提供一个解决方法,通过product flavor建立一个minSdkVersion大于21的新分支,用来debug。</li>     <li>Instant Run目前只能在主进程里运行,如果应用是多进程的,类似微信,把webView抽出来单独一个进程,那热、温拔插会被降级为冷拔插。</li>     <li>在Windows下,Windows Defender Real-Time Protection可能会导致Instant Run挂掉,可用通过添加白名单列表解决,具体操作自行Google</li>     <li>暂时不支持<a href="/misc/goto?guid=4959672631395371121">Jack compiler</a>,Instrumentation Tests,或者同时部署到多台设备。</li>    </ul>    <h2>操作</h2>    <ul>     <li><strong>下载</strong>:AS1.5及其以上的用户可以通过增量包直接升级到2.0或者2.1,1.5以下的,个人觉得直接重新官网下载一个就好了,不看好瞎折腾,觉得浪费时间。</li>     <li><strong>设置</strong>:Instant Run是默认开启的。设置路径:Preferences -> Build,Execution,Deployment -> Instant Run</li>     <li><strong>使用</strong>:和往常一模一样,只是你会发觉速度飙升,变快了。-0-</li>    </ul>    <p><br>  </p>    <p>文/<a href="/misc/goto?guid=4959672631480896400">oaosj</a>(简书)<br>  </p>