Enum 是 java 中一种包含固定常数的类型,当我们需要预先定义一些值时,我们使用 Enum.

1
2
3
4
public enum Season
{
WINTER, SPRING, SUMMER, FALL
}

我们通常为了在编译时期避免接受额外常量引起的错误.

使用 Enum 的缺点

每一个枚举值都是一个对象,在使用它时会增加额外的内存消耗,所以枚举相比与 Integer 和 String 会占用更多的内存.在一些旧的设备(<=2.2),一些性能问题就是由于 Enum 引起的.

较多的使用 Enum 会增加 DEX 文件的大小,会造成运行时更多的开销,使我们的应用需要更多的空间.

如果你的应用使用很多的 Enum ,最好使用Integer 或 String 替代他们,但是这样还会有问题.

解决方案

Android 提供了 TypeDef 注解库,这个注解确保特定的参数,返回值,或者变量引用为一个指定的集合范围,
IntDef**StringDef是两个非常有用的注解,来替换Enum,它们可以在编译时像枚举一样检测变量的范围.

如何使用?

让我们来看一个简单的实例来理解如何使用,下面的代码是一个ConstantSeason类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ConstantSeason {
public static final int WINTER = 0;
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
public ConstantSeason(int season) {
System.out.println("Season :" + season);
}
public static void main(String[] args) {
// Here chance to paas invalid value
ConstantSeason constantSeason = new ConstantSeason(5);
}
}

很不幸,这样不能保证用户用户传入的是合适的值-这里不是类型安全的.

我们来看一下使用枚举.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class EnumSeason {
public EnumSeason(Season season) {
System.out.println("Season :" + season);
}
public enum Season {
WINTER, SPRING, SUMMER, FALL
}
public static void main(String[] args) {
EnumSeason enumSeason = new EnumSeason(Season.SPRING);
}
}

现在,我们看一下如何使用扩展注解开完成上面的逻辑.

在你的项目中添加注解扩展库到你的 build.gradle文件

dependencies { compile ‘com.android.support:support-annotations:24.2.0’ }

然后让我们声明@IntDef常量

1
2
3
4
5
6
7
8
9
// Constants
public static final int WINTER = 0;
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
// Declare the @IntDef for these constants
@IntDef({WINTER, SPRING, SUMMER, FALL})
@Retention(RetentionPolicy.SOURCE)

Typedef 在这里使用 @interface来定义一个新的枚举注解类型,@IntDef**@StringDef**表示需要定义的类型,@Retention表示注解所存活的时间,在运行时,而不会存在. class 文件.

我们来使用上面定义的Typedef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AnnotationSeason {
public static final int WINTER = 0;
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
public AnnotationSeason(@Season int season) {
System.out.println("Season :" + season);
}
@IntDef({WINTER, SPRING, SUMMER, FALL})
@Retention(RetentionPolicy.SOURCE)
public @interface Season {
}
public static void main(String[] args) {
AnnotationSeason annotationSeason = new AnnotationSeason(SPRING);
}

现在,如果我们创建AnnotationSeason实例时传递不同的值,将会提示错误.

以相同的方式可以使用@StringDef

1
2
3
4
5
6
7
8
9
10
// Constants
public static final String WINTER = "Winter";
public static final String SPRING = "Spring";
public static final String SUMMER = "Summer";
public static final String FALL = "Fall";
// Declare the @ StringDef for these constants:
@ StringDef ({WINTER, SPRING, SUMMER, FALL})
@Retention(RetentionPolicy.SOURCE)
public @interface Season {}

这个视频是关于 Android 中使用 Enum 的性能问题.

结尾

Enum 增加了APK 的大小,比常量多5到10倍的内存占用,这是关于应用性能的最佳实践.

你可以在这学到更多关于支持注解库

Support Library Features Guide

Impove Code Inspection With Annotations