文章目录[x]
- 0.1:D8和R8
- 0.2:enum和when表达式
D8和R8
有3种编译器可以用来编译运行Android开发写的Kotlin代码。
- Kotlin编译器:可以运行并转换Kotlin代码为Java字节码。
- D8:它将Java字节码转换为Dex代码,这时就可以运行应用了。
- R8:用于优化和缩小应用(主要是ProGuard的替代品)
R8在默认情况下未开启,如果想使用R8则需要在build.gradle的minifyEnabled设置为true
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
这迫使R8可以优化并缩小应用。
enum和when表达式
enum class BlendMode{
OPAQUE,
FADE,
ADD,
TRANSPARENT
}
fun blend(blend:BlendMode){
when(blend){
BlendMode.OPAQUE->op()
BlendMode.FADE->fade()
BlendMode.ADD->add()
BlendMode.TRANSPARENT->trans()
}
}
fun add(){}
fun fade(){}
fun trans(){}
fun op(){}
假如声明了以上枚举类,然后when表达式来判断条件然后根据不同结果调用不同方法。编译成Java代码如下:
public static final void blend(@NotNull BlendMode blend) {
Intrinsics.checkParameterIsNotNull(blend, "blend");
switch(EnumsKt$WhenMappings.$EnumSwitchMapping$0[blend.ordinal()]) {
case 1:
op();
break;
case 2:
fade();
break;
case 3:
add();
break;
case 4:
trans();
}
}
...
// EnumsKt$WhenMappings.java
import kotlin.Metadata;
// $FF: synthetic class
@Metadata(
mv = {1, 1, 13},
bv = {1, 0, 3},
k = 3
)
public final class EnumsKt$WhenMappings {
// $FF: synthetic field
public static final int[] $EnumSwitchMapping$0 = new int[BlendMode.values().length];
static {
$EnumSwitchMapping$0[BlendMode.OPAQUE.ordinal()] = 1;
$EnumSwitchMapping$0[BlendMode.FADE.ordinal()] = 2;
$EnumSwitchMapping$0[BlendMode.ADD.ordinal()] = 3;
$EnumSwitchMapping$0[BlendMode.TRANSPARENT.ordinal()] = 4;
}
}
可以看出编译后的Java代码中的swtich还调用了生成枚举类中的数组。
这时由于二进制兼容性的原因,在枚举的序数值中,代码不能简单地应用这个值,因为它有可能会break(如果在项目中使用枚举,你更改了枚举的顺序,有可能破坏之前申请的顺序)。由此便有了EnumsKt$WhenMappings类中的静态代码块来执行映射操作。
如果我们在代码中有很多when语句和enum一起使用,就会生成很多类和数组。这会造成很大的内存和执行时间上的消耗。
一个好的解决方法就是使用R8,它会将编译后的代码优化为如下代码从而避免创建额外的类和数组:
public static final void blend(@NotNull BlendMode blend) {
Intrinsics.checkParameterIsNotNull(blend, "blend");
switch(blend.ordinal()) {
case 1:
op();
break;
case 2:
fade();
break;
case 3:
add();
break;
case 4:
trans();
}
}