Android中是否应该使用枚举Enum

在日常开发中,当遇到一些固定类型变量的申明,我们常常会想到Java中的枚举Enum,但是,在Android开发官网关于内存管理板块[Manage Your App’s Memory]有这么一段话

enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.

文中说到Enum会比静态常量多占用两倍以上的内存!关于这点,大家可以看看秋百万和胡凯做的详细论证,大家可以移步Android 中的 Enum 到底占多少内存?该如何用?Android性能优化典范 - 第3季

Enum的原理

我们首先举例一个枚举

1
2
3
public enum ProductState{
INITIAL, ON_SALE, SALED_OUT, STOP_SALE
}

通过javac命令编译成class文件,再通过javap反编译这个class文件的字节码内容,可以看到如下结果

1
2
3
4
5
6
7
8
9
10
11
12
➜ Downloads javac ProductState.java
➜ Downloads javap ProductState
Compiled from "ProductState.java"
public final class ProductState extends java.lang.Enum<ProductState> {
public static final ProductState INITIAL;
public static final ProductState ON_SALE;
public static final ProductState SALED_OUT;
public static final ProductState STOP_SALE;
public static ProductState[] values();
public static ProductState valueOf(java.lang.String);
static {};
}

由此可知,ProductState类被编译成继承自Enum的final类,其中申明的变量也被申明成final常量,它们都是不能被修改的

我们可以看到,上面的枚举申明非常简洁易懂,代码可读性非常好,当然这带来的代价就是内存占用会比静态常量申明要大

Android中替代枚举的方法

从Android Support Library19.1版本开始引入了一个新的注解库,其中包括了很多有用的元注解,可以用来修饰代码并且帮助发现bug,如@NonNull,@StringRes,@IntDef,@StringDef等等

这里我们就可以利用@IntDef来替代枚举,方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static final int INITIAL = 0;
public static final int ON_SALE = 1;
public static final int SALED_OUT = 2;
public static final int STOP_SALE = 3;
@IntDef({INITIAL, ON_SALE, SALED_OUT, STOP_SALE})
@Retention(RetentionPolicy.SOURCE)
public @interface ProductState {
}
private void initProductView(@ProductState int state){
...
}

总结

枚举Enum虽然在代码安全性和可读性性上都给非常好,但是在Android系统吃紧的内存上,我们还是应该避免使用枚举,可以用静态常量和注解等来替代

参考

Android 中的 Enum 到底占多少内存?该如何用?
关于Java中枚举Enum的深入剖析
Android性能优化典范 - 第3季
Android代码替代枚举的正确之道