Android D8 编译器 和 R8 工具(1)

本文介绍了AndroidStudio3.X后引入的D8和R8编译器,以及它们在DEX编译和代码优化中的作用,包括D8的性能提升、R8的混淆和压缩功能,以及Java8的脱糖过程。同时提到了如何配置和禁用这些工具。
摘要由CSDN通过智能技术生成

dex 过程

  • javac:用于将 .java 文件编译为 .class 文件;
  • desugar:用于将 Java 8 中的特性在 Android 平台上适配;
  • ProGuard:用于提出无用的 Java 代码并且做一些优化;
  • DX):将所有的 Java 代码转换为 DEX 格式。

Android Studio 3.X 以后,Google 分别引入 D8 编译器和 R8 工具作为新的 DEX 编译器和混淆压缩工具。

1. D8、R8 发展历程

Android Studio 版本Android Gradle Plugin 版本变更
3.13.0.1引入 D8
3.23.2.0引入 R8、D8 脱糖默认开启
3.43.4.0默认开启 R8
1.1 D8 编译器

GoogleAndroid Studio 3.1 版本中引入 D8 编译器作为默认的 DEX 字节码文件编译器。通过在 gradle.properties 中新增 android.enableD8=true 开启 D8 编译器。

D8 编译器特点是:

  • 编译更快、时间更短;
  • DEX 编译时占用内容更小;
  • .dex 文件大小更小;
  • D8 编译的 .dex 文件拥有相同或者是更好的运行时性能;

根据 Google Android 团队使用 DexD8 编译器的测试对比数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

d8 size.png

1.2 R8 工具

GoogleAndroid Studio 3.2 中引入 R8 作为 ProGuard 的替代工具,用于代码的压缩(shrinking)和混淆(obfuscation)。通过在 gradle.properties 中新增 android.enableR8 = true 开启 R8 工具。

Disables R8 for Android Library modules only.

android.enableR8.libraries = false

Disables R8 for all modules.

android.enableR8 = false

1.3 Android Studio 3.4 版本 D8 R8 变更

Android Studio 3.4 版本中,R8desugaringshrinkingobfuscatingoptimizingdexing 都合并到一步进行执行。在 Android Studio 3.4 以前的版本编译流程如下:

compile_with_d8_proguard.png

合并之后编译流程如下:

compile_with_r8.png

注意,如果我们在 build.gradle 中配置了 useProguard = false 则不管是否开启 R8 编译都会使用 R8 进行压缩代码。

2. 脱糖

Android Studio 为使用部分 Java 8 语言功能及利用这些功能的第三方库提供内置支持。默认工具链对 javac 编译器的输出执行字节码转换(称为 desugar),从而实现新语言功能。

脱糖即在编译阶段将在语法层面一些底层字节码不支持的特性转换为基础的字节码结构,(比如 List 上的泛型脱糖后在字节码层面实际为 Object); Android 工具链对 Java8 语法特性脱糖的过程可谓丰富多彩,当然他们的最终目的是一致的:使新的语法可以在所有的设备上运行。

经过上面 D8R8 的了解,D8 已经支持脱糖,让 Java 8 提供的特性(如 lambdas)可以转换成 Java 7 特性。把脱糖步骤集成进 D8 影响了所有读或写 .class 字节码的开发工具,因为它会使用 Java 8 格式。可以在 gradle.properties 中禁用脱糖。

android.enableIncrementalDesugaring=false.
android.enableDesugar=false

2.1 Lambda 表达式

Java 8 中一个重大变更是引入 Lambda 表达式。

public class Lambda {
public static void main(String[] args) {
logDebug(msg-> System.out.println(msg), “HelloWorld”);
}

static void logDebug(Logger logger, String msg) {
logger.log(msg);
}

@FunctionalInterface
interface Logger {
void log(String msg);
}
}

通过 javac 指令将上面的 Lambda.java 转换为字节码。

$javac Lambda.java

接下来通过 javap -v 指令查看字节码的详细内容:

dengshiweideMacBook-Pro:Desktop dengshiwei$ javap -v Lambda.class
Classfile /Users/dengshiwei/Desktop/Lambda.class
Last modified 2019-5-12; size 1120 bytes
MD5 checksum 67301305720e60d4ef1ff286769768e6
Compiled from “Lambda.java”
public class Lambda
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #9.#25 // java/lang/Object.“”😦)V
#2 = InvokeDynamic #0:#30 // #0:log:()LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 9: Logger; #̲3 = String …Logger;Ljava/lang/String;)V
#5 = InterfaceMethodref #10.#33 // LambdaKaTeX parse error: Expected 'EOF', got '#' at position 34: …lang/String;)V #̲6 = Fieldref …Logger
#11 = Utf8 Logger
#12 = Utf8 InnerClasses
#13 = Utf8
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 main
#18 = Utf8 ([Ljava/lang/String;)V
#19 = Utf8 logDebug
#20 = Utf8 (LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 29: …lang/String;)V #̲21 = Utf8 …mainKaTeX parse error: Expected 'EOF', got '#' at position 3: 0 #̲22 = Utf8 …Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#28 = MethodType #22 // (Ljava/lang/String;)V
#29 = MethodHandle #6:#42 // invokestatic Lambda.lambda$mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲30 = NameAndTyp…Logger;
#31 = Utf8 HelloWorld
#32 = NameAndType #19:#20 // logDebug:(LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 29: …lang/String;)V #̲33 = NameAndTyp…Logger
#41 = Methodref #50.#51 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲42 = Methodref …mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲43 = Utf8 …Logger;
#45 = Utf8 java/lang/System
#46 = Utf8 out
#47 = Utf8 Ljava/io/PrintStream;
#48 = Utf8 java/io/PrintStream
#49 = Utf8 println
#50 = Class #53 // java/lang/invoke/LambdaMetafactory
#51 = NameAndType #54:#57 // metafactory:(Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲52 = NameAndTyp…mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲53 = Utf8 …Lookup
#56 = Utf8 Lookup
#57 = Utf8 (Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲58 = Class …Lookup
#60 = Utf8 java/lang/invoke/MethodHandles
{
public Lambda();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.“”😦)V
4: return
LineNumberTable:
line 1: 0

public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: invokedynamic #2, 0 // InvokeDynamic #0:log:()LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 26: … ldc #̲3 …Logger;Ljava/lang/String;)V
10: return
LineNumberTable:
line 3: 0
line 4: 10

static void logDebug(Lambda$Logger, java.lang.String);

学习福利

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
g-Enqiixix-1714642724759)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值