枚舉最大的作用是提供了類型安全。為了彌補(bǔ)Android平臺不建議使用枚舉的缺陷,官方推出了兩個(gè)注解,IntDef和StringDef,用來提供編譯期的類型檢查。
首先,引入依賴包:
implementation 'com.android.support:support-annotations:27.1.0'
定義一個(gè)注解
public @interface TaskStatus {
}
是的,類似于接口的定義,加個(gè) @ 符號。
注解一般使用步驟
那么對于上面的枚舉和常量都不 work 的場景,如何使用枚舉解決呢?
- 定義注解類,添加常量
@Retention(RetentionPolicy.SOURCE)
public @interface TaskStatus {
int UN_KNOW = -1;
int UN_START = 0;
int PROGRESSING = 1;
int COMPLETED = 2;
}
和接口成員一樣,注解類的成員默認(rèn)就是 public static final 修飾的。
@Retention(RetentionPolicy.SOURCE) 表示告訴編譯器,該注解是源代碼級別的,生成 class 文件的時(shí)候這個(gè)注解就被編譯器自動去掉了。
doSth() 方法:
public class TaskHelper {
public static void doSth(@TaskStatus int status){
switch (status){
case TaskStatus.UN_KNOW:
//do something
break;
case TaskStatus.UN_START:
break;
case TaskStatus.PROGRESSING:
break;
case TaskStatus.COMPLETED:
break;
}
}
}
可以看出,doSth() 方法的參數(shù)是 int 類型的,但是使用 @TaskStatus 進(jìn)行了注解,這樣外界就無法傳遞 TaskStatus之外的成員作為參數(shù)了。
- 調(diào)用
TaskHelper.doSth(TaskStatus.UN_START);
在調(diào)用時(shí),IDE 會提示 @TaskStatus int status,提醒我們傳入 TaskStatus 類型的值。
同時(shí),調(diào)用者如果再隨便傳入一個(gè) int 值,雖然可以運(yùn)行,但代碼會爆紅,lint 檢查將會給與警告:
Must be one of: TaskStatus.UN_KNOW, TaskStatus.UN_START, TaskStatus.PROGRESSING, TaskStatus.COMPLETED
如此,保證了類型安全。但也只是警告,仍然可以運(yùn)行,但總比沒有警告強(qiáng)多了。
補(bǔ)充
其實(shí)這種用法在 Android 源碼中屢見不鮮,比如 Resources 下的 getDrawable() 方法:
public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
final Drawable d = getDrawable(id, null);
//...
return d;
}
使用時(shí),我們一般會這么用:
getResources().getDrawable(R.drawable.ic_launcher);
雖然是 int 值,但是當(dāng)我們這么用時(shí):
getResources().getDrawable(111);
就會爆紅并提示:
Expected resource of type drawable
再補(bǔ)充一點(diǎn),為了防止在我們定義的常量值重復(fù),我們還可以使用Android 注解支持庫(support-annotations)中的 @IntDef 來限定常量不允許重復(fù):
@IntDef({
TaskStatus.UN_KNOW,
TaskStatus.UN_START,
TaskStatus.PROGRESSING,
TaskStatus.COMPLETED
})
@Retention(RetentionPolicy.SOURCE)
public @interface TaskStatus {
int UN_KNOW = -1;
int UN_START = 0;
int PROGRESSING = 1;
int COMPLETED = 2;
}