安装
让我们从安装开始,这样你就可以跟着一步一步的来。
第一个要安装的就是Android Studio 2.0 Preview 3b,在 Canary Channel上有提供。要把更新channel转换到Canary,只需点击Help -> Check for Update…并把最上面的下拉菜单改为 Canary Channel,完了之后,再次检查更新然后Android Studio 2.0 就会安装在你的机器上了。
安卓模拟器2.0是和Android SDK Tools v25(或者更新)的版本一起 的。所以接下来你要安装的就是Android SDK Tools v25 rc1 ,它可以通过SDK Manager来完成。以及安装最新的 Intel x86 Emulator Accelerator (HAXM installer),并且下载的只是一个安装器,所以需要在SDK里手动安装,路径如下:extras/intel/Hardware_Accelerated_Execution_Manager
有时候安装时会报错,需要设置控制面板->程序与功能->启用或关闭Windows功能->去掉 Hyper-V选项,就可以成功安装了。
最后是下载Android 5.0 - Google APIs Intel x86 Atom System Image rev 10,把它作为模拟器的rom镜像。
这样就准备完毕,可以使用了。
使用过程中发现太吃内存了这个模拟器,运存8G以上才可能不太卡。
emulator: ERROR: Couldn't find crash service executable
C:\Users\user\AppData\Local\Android\sdk\tools\emulator64-crash-service.exe
...
虽然不懂为什么报这个,但是我现在是直接无视它运行模拟器的呃。。。
Update Project 使得能够使用Instant Run功能
首先你需要去设置中启用Instant Run:
新项目需要在 Build, Execution, Deployment → Instant Run 点击 Update Project,然后点击 OK。
其实这一个设置就是在更新你项目的.gradle文件,并且使用最新版本的Android gradle插件,使得Instant Run 功能生效。
更新后的.gradle文件如下:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-alpha1'
}
}
好,现在可以来试试运用一下Instant Run 。
点击”Run“ 使你的程序在模拟器或者设备上跑起来~
我测试使用的设备是:Meizu M1 Note(Android 5.1 ,API 22)
测试代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button run;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
run = (Button) findViewById(R.id.button);
run.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button:
}
}
}
编译运行,测试界面为:
添加Toast:
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button:
Toast.makeText(MainActivity.this, "Instant Run!!", Toast.LENGTH_SHORT).show();
}
现在,只要点击工具栏上的Instant Run按键就可以在不重新安装apk的前提下修改代码了。
你会发现,系统瞬间就响应了你的点击行为,并且发出一条提示:
Applied changes,restarted acticity
现在,点击按键,你会发现你已经运行的是修改后的代码,是不是感觉特别棒!
可惜现在这个功能估计还在研发阶段,不是所有的代码修改情况都支持,支持该功能的情况不多,如下:
代码改变 | 是否支持Intant Run |
---|---|
改变实例方法实现 | 是 |
改变静态方法实现 | 是 |
添加或删除一个类 | 是 |
添加、删除或修改一个字符串资源 | 支持但是需要活动重启 |
以下为不支持Instant Run 的情况:
在我测试的情况来看,这个功能还不够稳定,代码修改后,经常不会触发Instant Run 的效果,而是直接重新安装。
但我觉得我大谷歌应该很快就完善好这一如此“便民”的功能。
google官方关于Instant Run特性的介绍在这里:https://sites.google.com/a/android.com/tools/tech-docs/instant-run,按其所述,运行FloatingActionButtonBasic样例,实验Instant Run,豪爽豪爽。
但是,修改方法竟然不用重启Activity,这是怎么做到的?
阅读一帆关于几个热补丁思路的介绍,你会发现andfix和dexposed采用jni hook方法,不用重启就能修复,而Nuwa的ClassLoader思路因为类被虚拟机加载后,不会重新加载,所以需要重启。Instant Run是怎么实现不重启加载的呢,难道也是jni hook?
和nuwa类似,一个插件一个库,Instant Run用的是gradle plugin 2.0.0-alpha1和instant-run.jar。
gradle plugin 2.0.0-alpha1主要有两个作用:
第一次运行,应用transform API修改字节码。
输出目录为:
Application/build/intermediates/transforms/instantRun/debug/folders/1。
给所有的类添加change字段
change为IncrementalChange类型,IncrementalChange是个接口,该接口后面会讲。
修改类的全部方法
新的逻辑是:如果change不为空,去调用 change的access dispatch方法,参数为方法签名字符串和方法参数数组,否则调用原逻辑。
后续运行,dx补丁类,生成补丁dex。
输出目录为:
Application/build/intermediates/transforms/instantRun/debug/folders/4000。
被修改类对应的补丁类
补丁类,并不是你修改后的类,而是由gradle plugin自动生成,实现了IncrementalChange接口的类。
该类类名在原名后面添加override,复制修改后类的大部分方法,实现IncrementalChange 接口的accessdispatch方法,该方法会根据传递过来的方法签名,调用本类的同名方法。
只要把原类的change字段设置为该类,那就会调用该类的accessdispatch方法,就会使用修改后的方法了。
被修改类的记录类
AppPatchesLoaderImpl记录了所有被修改的类,也会被打进补丁dex。
instant-run.jar的路径为Application/build/intermediates/incremental-runtime-classes/debug/instant-run.jar。
instant-run.jar是gradle plugin帮我们自动打到dex中去的,省去了compile dependency这一步。它的主要作用有两个:
设置原类的$change字段为补丁类
需要对被修改的类设置change字段,那怎么知道哪些类被修改了?
AppPatchesLoaderImpl类不但记录了全部被修改的类,还提供load方法支持设置被修改原类change字段,当收到补丁通知时,只需新建一个DexClassLoader,去反射加载补丁dex中的AppPatchesLoaderImpl类,调用load方法即可,load方法中会去加载全部补丁类,并赋值给对应原类的change。
重启加载补丁类
重启后怎么办?原来的补丁文件需要加载进来。
IncrementalClassLoader会在Application中去加载该应用cache目录中的补丁dex,把它设置为默认PathClassLoader的parent,由于ClassLoader采用双亲委托模型,会先去parent查找类,所以就可以加载补丁类了。
google的介绍中,也提到了Instant Run的一些局限之处,比如变量、添加删除方法等,当然这一切都会持续优化,gradle plugin 2.0也还仅仅是个alpha版本而已。
Instant Run的实现思路蛮笨的,几乎所有的方法都修改逻辑,但不用重启这一点很赞,用这个思路可以搞一个热修复库了,有官方背景的库。
本文主要是探究Instant Run处理代码变化的思路,对资源变化没有分析,对于一些细节比如server实现、socket传输、application替换、updateMode处理亦未提及。
原文出处:http://jiajixin.cn/2015/11/25/instant-run/