Android Studio升级到2.0之后,新增了Instant Run功能,该功能可以热替换apk中的部分代码,大幅提高测试安装的效率。

但是,由于我的项目中自定义了一些ClassLoader,当使用InstantRun时,经常出现class加载不正确的问题。分析后原因如下。

使用Instant Run编译出的apk里面会多出几个dex文件,和一个instant-run.zip,这个zip里也是一堆dex文件:

所以推测,instant Run的实现原理是:

根据代码结构,将App的源码分割成多个dex,然后使用自定义的classloader来加载他们,当然这个自定义的classloader也要继承BaseDexClassLoader,因为BaseDexClassLoader里有个DexPathList,这个所谓的List里存的是多个dex的文件信息,所以当某段代码修改时,只需编译和替换相应的dex文件即可(这同样也是MultiDex的实现原理)。

下面我们简单验证一下。

首先正常的apk运行时,其classloader打印出来是这样的:

dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.zkw.hostdemo-1/base.apk"],nativeLibraryDirectories=[/data/app/com.zkw.hostdemo-1/lib/arm, /system/lib, /vendor/lib, system/vendor/lib, system/vendor/lib/egl, system/lib/hw]]]

而使用Instant Run运行起来的apk,其classloader打印出来长这样:

com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLoader[DexPathList[[dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-support-annotations-23.3.0_6be31c7c3de045eced09b0e58c45c46ba1a8b4da-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_9-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_8-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_7-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_6-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_5-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_4-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_3-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_2-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_1-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_0-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-ormlite-core-4.47_2aa30d6da8ed45bfc6255e592f80eb5f44eace4c-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-ormlite-android-4.47_a7ee90c985672a4cd4bdfca79190a330465fcdb0-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-lecore_4c1e07fda866033d90832ceae724962d4943e790-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-internal_impl-23.1.1_12c3206fb094d3315355dc809fcd39ad94f6e5e8-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-fastjson-1.1.45.android_317ce285230b187682809682934f3690b4d9580d-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-com.android.support-support-v4-23.1.1_1cfecee433501e7056d02c08b2393c569c575b33-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-com.android.support-multidex-1.0.1_a3117677a6ad7ee678ee3f3a4af434c4d08ee7ba-classes.dex"],nativeLibraryDirectories=[/data/app/com.zkw.hostdemo-1/lib/arm, /system/lib, /vendor/lib, system/vendor/lib, system/vendor/lib/egl, system/lib/hw]]]

很长吧,发个截图:

可以看到这个ClassLoader是:com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLoader,DexPathList对应着instant-run.zip里的所有dex。

到这里,感觉基本符合我的猜想,但是这个IncrementalClassLoader是如何添加到设备中的,又如何在运行时起作用的,我们接着分析。

instant run运行的apk里,和class有关的就是classes.dex、classes2.dex和instant-run.zip里的dex。

通过观察命名和反编译,我发现instant-run.zip里的dex都是和我们app代码相关的,而classes.dex和classes2.dex是AndroidStudio编译时自己添加的,其中classes2.dex最重要,我们反编译看看:

终于看到了熟悉的IncrementalClassLoader,那这个classloader是怎么生效的呢,我们看看BootstrapApplication的源码(可想而知,AndroidManifest文件中的application属性也被Android Studio改了):

注意标绿的那行,继续进去看看(那行下面有个createRealApplication(),其实就是通过反射获取app自定义的Application,然后做对应的操作):

灰色的那行就是安装IncrementalClassLoader的地方,进入IncrementalClassLoader的inject()看看,

源码中可以看到,Studio其实就是利用反射,将自己的IncrementalClassLoader设置成app中默认ClassLoader的parent,这样就拦截了所有类加载的动作,从而实现了对多个dex文件的动态加载。

到此,原理分析结束。

所以如果你的app里用到了自定义的ClassLoader,请谨慎使用Instant Run!

谢谢阅读,转载请注明出处。

[原创]Android Studio的Instant Run(即时安装)原理分析和源码浅析的更多相关文章

  1. AndroidKiller报.smali文件丢失问题解决(关闭Android Studio的Instant Run)

    第一节编写一个Android程序里我们生成了一个验证激活码的apk,当我们输入的激活码正确时才能注册成功,输入错误时注册失败. 现在我们想输入错误的激活码也能注册.我们用Android反编译工具进行反 ...

  2. android studio2.0出现的gradle问题,instant Run即时运行不了.

    android studio 2.0出现的gradle问题: instant Run即时运行不了.经历了几乎9个preView版本的AS2.0,终于迎来了正式版,然而晴天我的霹雳,好不容易装好的2.0 ...

  3. Android新特性Instant Run详解

    关于 Instant Run Android Studio 2.0 中引入的 Instant Run 是 Run 和 Debug 命令的行为,可以大幅缩短应用更新的时间.尽管首次构建可能需要花费较长的 ...

  4. Android Studio和SDK下载、安装和环境变量配置

    win10下Android Studio和SDK下载.安装和环境变量配置                                                               - ...

  5. Android studio Unable to run mksdcard SDK tool

    /******************************************************************************************** * Andr ...

  6. Android Studio(一):介绍、安装、配置

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  7. Android Studio 1.0 苹果电脑安装配置

    ​ 前言 近日Google终于不负众望,发布了期待已久的Android Studio 1.0正式版.小编自己是Android开发者,之前使用过Eclipse,也试用过Android Studio 0. ...

  8. Android Studio中mac上面的安装

    Android Studio中mac上面的安装 学习了:https://blog.csdn.net/xianrenli38/article/details/79347170 http://www.an ...

  9. Android Studio 和 SDK 下载、安装和环境变量配置

    转Android Studio 和 SDK 下载.安装和环境变量配置https://blog.csdn.net/hahahhahahahha123456/article/details/8065135 ...

随机推荐

  1. C#执行OracleHelper

    /// <summary> /// 执行存储过程获取带有Out的参数 /// </summary> /// <param name="cmdText" ...

  2. C语言 线性表 顺序表结构 实现

    一个能够自动扩容的顺序表 ArrList (GCC编译). #include <stdio.h> #include <stdlib.h> #include <string ...

  3. 对VM挂载新加入的磁盘

    在虚拟机配置中增加磁盘后,启动Linux,使用root登录. 首先查看未分区的磁盘,使用下面命令: ## 查看未使用的磁盘 fdisk -l 磁盘/dev/sdb后面没有任何分区,是新挂载的磁盘 输入 ...

  4. 【转】关于KDD Cup '99 数据集的警告,希望从事相关工作的伙伴注意

    Features From: Terry Brugger Date: 15 Sep 2007 Subject: KDD Cup '99 dataset (Network Intrusion) cons ...

  5. 【原】关于使用jieba分词+PyInstaller进行打包时出现的一些问题的解决方法

    错误现象: 最近在做一个小项目,在Python中使用了jieba分词,感觉非常简洁方便.在Python端进行调试的时候没有任何问题,使用PyInstaller打包成exe文件后,就会报错: 错误原因分 ...

  6. Atitit.javascript 实现类的方式原理大总结

    Atitit.javascript 实现类的方式原理大总结 1. 实现类的式::构造方法方式:原型方式:构造方法+原型的混合方式 1 2. 原型方式(function mode)经典式..实现属性推荐 ...

  7. atitit.压缩算法 ZLib ,gzip ,zip 最佳实践 java .net php

    atitit.压缩算法 ZLib ,gzip ,zip   最佳实践  java .net php 1. 压缩算法的归类::: 纯算法,带归档算法 1 2. zlib(适合字符串压缩) 1 3. gz ...

  8. css3多列显示

    columen-width:定义单列显示的宽度.初始值是auto,适用于不可替代的块级元素,行内块元素和单元格,表格元素除外. 目前Webkit引擎支持-webkit-column-width,Moz ...

  9. Leetcode 67 Add Binary 大数加法+字符串处理

    题意:两个二进制数相加,大数加法的变形 大数加法流程: 1.倒置两个大数,这一步能使所有大数对齐 2.逐位相加,同时进位 3.倒置两个大数的和作为输出 class Solution { public: ...

  10. Vue.js:轻量高效的前端组件化方案(转载)

    摘要:Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在GitHub上已经有5000+的star.本文将从各方面对Vue ...