目录

Android 中如何使用annotion替代Enum

抛弃枚举, 在android中一个更好的方法替代他.

起因

阅读原文

当我们想从一些预定义的常量中使用一个变量我们能怎么做. 我可以声明常量并给他们赋值. 我们假设某一个值是表示今天,他可以从周日到周六有不一样的值来指定,我们在java中可以这样使用整数型常量.

```

public class Main {	
public static final int SUNDAY = 0;
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;

private int currentDay = SUNDAY;

public static void main(String[] args) {
  	 // TODO Auto-generated method stub
  		Main obj = new Main();
  		obj.setCurrentDay(WEDNESDAY);

   	int today = obj.getCurrentDay();

   	switch (today) {
   	case SUNDAY:
      	 System.out.println("Today is SUNDAY");
       	break;
   	case MONDAY:
      	 System.out.println("Today is MONDAY");
      	 break;
   	case TUESDAY:
        System.out.println("Today is TUESDAY");
        break;
   	case WEDNESDAY:
        System.out.println("Today is WEDNESDAY");
        break;
   	case THURSDAY:
        System.out.println("Today is THURSDAY");
        break;
   	case FRIDAY:
      	 System.out.println("Today is FRIDAY");
        break;
   	case SATURDAY:
    	   System.out.println("Today is SATURDAY");
        break;

    default:
        break;
    }
}

public void setCurrentDay(int currentDay) {
    this.currentDay = currentDay;
}

public int getCurrentDay() {
    return currentDay;
}

}
```

问题

这段代码看似已经实现功能, 但是有问题存在的因为我可以设置任何的整数型的值给当前的currentDay.

obj.setCurrentDay(100);

方案1 使用Enum

这样即使我们设置了超出了currentDay没有实际意义值得时候, 编译器却没有给我们任何的提示. 然后在 switch语句中将错过这些值. 所以java给了我们一个解决方案就是使用枚举(Enum)和Enumerarion. 我们可以使用Enum重写之前的代码.

```

public class Main {

public enum WeekDays {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

private WeekDays currentDay = WeekDays.SUNDAY;

public static void main(String[] args) {
    // TODO Auto-generated method stub
    Main obj = new Main();
    obj.setCurrentDay(WeekDays.WEDNESDAY);

    WeekDays today = obj.getCurrentDay();

    switch (today) {
    case SUNDAY:
        System.out.println("Today is SUNDAY");
        break;
    case MONDAY:
        System.out.println("Today is MONDAY");
        break;
    case TUESDAY:
        System.out.println("Today is TUESDAY");
        break;
    case WEDNESDAY:
        System.out.println("Today is WEDNESDAY");
        break;
    case THURSDAY:
        System.out.println("Today is THURSDAY");
        break;
    case FRIDAY:
        System.out.println("Today is FRIDAY");
        break;
    case SATURDAY:
        System.out.println("Today is SATURDAY");
        break;

    default:
        break;
    }
}

public void setCurrentDay(WeekDays currentDay) {
    this.currentDay = currentDay;
}

public WeekDays getCurrentDay() {
    return currentDay;
}

}

```

这样我们的currentDay,set只接收Enum类型, 而Enum里面有什么使我们预先定义好的.这样就解决了之前出现的问题.这是一个好的解决方案.所以我们应该在以后根据场景使用它, 但是在Android中还是会有些问题的

方案2 使用android特有的魔术变量注解替代Enum

Enum in Android 枚举Enum在java中是一个完整的类. 而枚举中的每一个值在枚举类中都是一个对象. 所以在我们使用时枚举的值将比整数常量消耗更多的内存. 当我们使用枚举在安卓应用中, 如果我们的程序本身内存消耗就比较大,或者是一个游戏的应用程序. 那么我们最好使用常量来替代枚举. 但之前的问题仍然存在.

那么有什么好的办法么?

当然, Android 支持注解库中有一些好用的annotation helper 我们可以使用它们来解决我们之前的问题(在编译代码时期).

IntDefStringDef 是两个魔术变量注解. 使用这个两个来替代之前使用的Enum. 它将帮助我们在编译代码时期像Enum那样选择变量的功能. 接下来我们来使用IntDef来替换Enum看一下.

```

public class MainActivity extends Activity {

public static final int SUNDAY = 0;
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;

@IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface WeekDays {}

@WeekDays int currentDay = SUNDAY;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setCurrentDay(WEDNESDAY);

    @WeekDays int today = getCurrentDay();

    switch (today){
        case SUNDAY:
            break;
        case MONDAY:
            break;
        case TUESDAY:
            break;
        case WEDNESDAY:
            break;
        case THURSDAY:
            break;
        case FRIDAY:
            break;
        case SATURDAY:
            break;
        default:
            break;
    }

}

public void setCurrentDay(@WeekDays int currentDay) {
    this.currentDay = currentDay;
}

@WeekDays
public int getCurrentDay() {
    return currentDay;
}
}

```

现在我们不能直接用一个int值赋值给currentDay变量, 或者在set赋值的时候只能传入currentDay变量被注解所规定的魔术注解IntDef中的常量引用(而不是引用对应的引用值). 当我们使用赋一些没有意义的值时, 编译器将给我们一些警告让我们修改.

如果我们使用过的是Android Studio开发的话, IDE将给我们关于如果使用的建议.

创建步骤

我们可以拆解一下步骤.

首先如果想要这个特证,你应该添加 support-annotations library 到你的项目中去, 如果你使用AS,可以使用gradle的依赖.

```
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
...
compile 'com.android.support:support-annotations:22.0.0'
}
```

如果你的项目已经依赖这个:com.android.support:appcompat-v7, 那或许不需要单独添加上述库的依赖

1.首先声明常量

```
public static final int SUNDAY = 0;
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;
```

2.创建一个注解,声明魔术变量@IntDef(或者@StringDef其实后面传入的为String类型常量)并给其添加想预定义的int常量

```
@IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface WeekDays {}
```

3.给变量currentDay使用注解

```
@WeekDays int currentDay ;
//这时currentDay 不会接收weekDays以外的所有值, 即使是IntDef中常量名对应的值也不可以, 只能使用weekDays常量引用
```

4.如果我们要声明currentDay的setter和getter,可以这样使用来限制问题

```
public void setCurrentDay(@WeekDays int currentDay) {
	this.currentDay = currentDay;
}

@WeekDays
public int getCurrentDay() {
	return currentDay;
}	
```

如果你想了解更多关于注解支持库的介绍,come here (自备梯子).