申明:电脑最终没砸成。
问题描述:
AS使用jdk1.8后,jack编译器导致AS 的instant run 功能失效,导致每次都是重新来一次,如果项目复杂的话会特别耗时间
问题发现的过程:
做一个组件化demo的时候,使用了jdk1.8。结果每次项目编译都是10分钟以上,然后instant run也启动不了(as提示instant run disable when jack....)。
当时给这个问题下了两个结论:
- 电脑配置实在太渣了
由于自己的电脑配置很渣,所以一直以为是电脑问题(之前用的公司台式机,该项目用的自己的笔记本(i3)。都在筹划着购买新电脑了。
- 组件化后编译会变慢
这个结论有点牵强,如果真是这个问题网上肯定会有人碰到,结果各种搜也没找到跟这个相关的。
后来使用gradle build-profile命令查看编译耗时情况如下:
:app 5m47.67s (total)
task | 所用时间 |
---|---|
:app:transformClassesWithPreJackPackagedLibrariesForDebug | 2m7.70s |
:app:transformJackWithJackForRelease | 1m28.25s |
:app:transformJackWithJackForDebug | 1m2.54s |
:app:lint | 22.736s |
:app:mergeDebugResources | 12.305s |
查看到主要耗时就是这个jack编译造成的,我擦的,怎么又看到了这个Jack,这货TMD是谁啊?
经过各种搜才知道jdk1.8跟as的instant run冲突,然后恢复成1.7.发现不只是instant run可以使用了,连第一次的编译速度也变成了2分钟左右(首次没有instant run)。看来android对java8的支持挺坑的。当然主要是我电脑太渣所以差距才会这么大,如果电脑配置很高,估计连这个问题都发现不了吧。
问题原因:
官方文档中文版 使用 Java 8 语言功能
返回使用jdk1.7方式如下:把以下代码注释掉
defaultConfig {
applicationId "com.example.administrator.mousestore"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// jackOptions {
// enabled true//为true时使用jdk1.8的jack编译
// }
}
// compileOptions {
// sourceCompatibility 1.8
// targetCompatibility 1.8
// }
另外,如果你有其他module的话也需要处理下。
如果module是java module那请修改如下代码:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
把sourceCompatibility和targetCompatibility改成1.7
关于jack编译器(以下copy知乎上的一个回答):
Jack是Android从Java 7到Java 8过渡时期的一次失败尝试。
具体来讲,在Java 7之前,Android app是使用javac+dx的方式编译出来的,即源代码java程序先由javac编译成可以在JVM上执行的class文件,再由dx工具将class文件转换成dex文件,这个dex文件就是apk里面的二进制代码。如图所示:
<figure>
<noscript><img src="https://pic1.zhimg.com/50/v2-e3c77e6bd01916f61dd82672a3f67584_hd.jpg" data-rawwidth="800" data-rawheight="318" class="origin_image zh-lightbox-thumb" width="800" data-original="https://pic1.zhimg.com/v2-e3c77e6bd01916f61dd82672a3f67584_r.jpg"></noscript>

</figure>
Java 8的时候,Google的工程师们推出了Jack(Java Android Compiler Kit),想要尝试用这套新的工具链替换原来的javac + dx,即直接从java代码编译到dex文件,如图:
<figure>
<noscript><img src="https://pic4.zhimg.com/50/v2-7f5d8ea5c249e7e31ed6cdfd0097205e_hd.jpg" data-rawwidth="783" data-rawheight="296" class="origin_image zh-lightbox-thumb" width="783" data-original="https://pic4.zhimg.com/v2-7f5d8ea5c249e7e31ed6cdfd0097205e_r.jpg"></noscript>

</figure>
为什么要替换原有的javac+dx 方法呢?原因可能有:
- 从java直接到dex,减少中间结果,可以加快编译速度;
- Jack工具直接处理java源代码,有更大的编译优化空间;
- javac属Oracle公司所有,Google想要摆脱Oracle的制约(猜测)。
总之Jack就这样被推出了,而且它能完成基本编译任务,也完全可以用来开发中小型应用。
但是,有很多基本编译功能之外的其他功能是Jack很难支持的,例如bytecode分析和重写,annotation处理等等。对于个人开发者来说,最直观的影响就是Android Studio里面的instant run功能,即app源代码被修改一小部分之后增量地编译修改的部分,从而更快地运行app。Instant run这个功能需要bytecode可分析和重写,所以Jack无法支持,必须每次从头开始编译,于是用了Jack之后,app编译会明显变慢。
正因为这些附加功能的缺失,Jack却一直无法很好地为大型企业及开源社区服务,而解决这些问题又很难。
于是,在今年3月,Google终于宣布,放弃了Jack,重新尝试用javac+dx的方法在Android里支持Java 8。
Over time, we realized the cost of switching to Jack was too high for our community when we considered the annotation processors, bytecode analyzers and rewriters impacted. -- James Lau, Product Manager
Jack的故事到这里就结束了,一次有意义的尝试宣告破产,令人惋惜。不知道未来还有没有可能卷土重来。
网友评论