众所周知,在Android官方的性能优化相关课程中曾经提到使用枚举存在的性能问题,不建议在Android代码中使用枚举:
Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android
Effective Java中列举了使用枚举的众多优点,相对于Int
静态常量来说,枚举最大的作用是提供了类型安全。看看如下的栗子:
class Person {
public static final int MALE = 0;
public static final int FEMALE = 1;
private int sex;
public void setSex(int sex) {
this.sex = sex;
}
public String getSexDes() {
if(sex == 0) {
return "男";
}else if(sex == 1){
return "女";
}else {
throw new IllegalArgumentException("什么鬼性别?");
}
}
}
因为调用者可以在setSex()
传递任何整数,那么导致出现了非男非女的性别,而使用枚举可以有效避免上述情况。
为了弥补Android平台不建议使用枚举的缺陷,官方推出了两个注解,IntDef
和StringDef
,用来提供编译期的类型检查,使用灰常简单,下面以IntDef
为栗:
首先,引入依赖包:
compile 'com.android.support:support-annotations:22.0.0'
然后就可以在代码中使用了:
public class MainActivity extends Activity {
public static final int MALE = 0;
public static final int FEMALE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
Person person = new Person();
person.setSex(MALE);
((Button) findViewById(R.id.test)).setText(person.getSexDes());
}
class Person {
@SEX
private int sex;
public void setSex(@SEX int sex) {
this.sex = sex;
}
@SEX
public int getSex() {
return sex;
}
public String getSexDes() {
if (sex == MALE) {
return "男";
} else {
return "女";
}
}
}
@IntDef({MALE, FEMALE})
@Retention(RetentionPolicy.SOURCE)
public @interface SEX {
}
}
这里我们可以看到,@SEX
注解可以放到属性定义,参数,返回值等地方对数据类型进行限制。如果我们直接赋值一个Int
参数给setSex()
,IDE会直接报错:

然而如果你曾经看过这篇文档,你就知道,这仅仅是AS的静态代码检查而已,就像上面的代码,尽管IDE已经报错,你还是可以直接Run Application
,而且也可以成功运行。这倒是可以理解,因为我们这个注解本身就是RetentionPolicy.SOURCE
,只能给代码检查工具使用。
它对应的AS代码检查项如下:

在lint中,对应的选项是WrongConstant
:
WrongConstant
Summary: Incorrect constant
Priority: 6 / 10
Severity: Error
Category: Security
Ensures that when parameter in a method only allows a specific set of
constants, calls obey those rules.
OK,以上就是在Android代码中如何替换枚举类型的正确之道。
更新2015-11-10:
1、引入注解的support包,可以使用provided
,避免打入正式发布的APK中。
2、对于是否替换Android中的枚举,需要分不同的情况,比如上文中提及的场景也是枚举使用的大部分场景:仅仅提供类型安全,那么我们可以考虑通过注解来替换;如果我们需要将数据和枚举常量关联起来,在枚举中声明域,然后编写一个带有数据的构造器,那么还是考虑把枚举留下吧。
网友评论