安卓開發(fā)中會有很多地方使用到注解,有些是Java中的霜医,有些是三方框架所帶的齿拂。
Java中的常見的幾種標(biāo)準(zhǔn)注解
@Override 表示當(dāng)前的方法定義將覆蓋父類中的方法。
@Deprecated 表示廢棄的意思肴敛,使用了該注解的方法或者對象署海,則會有提示。
@SuppressWarnings 關(guān)閉不當(dāng)?shù)木幾g器警告信息
上述幾種標(biāo)準(zhǔn)注解我們在安卓開發(fā)的過程中經(jīng)常會看到值朋,不過我們平常使用的注解還有一類并不是Java提供給我們的叹侄,而是我們自定義的。自定義注解需要使用到Java提供的幾個(gè)元注解昨登。元注解是用在注解上的注解趾代。
Java提供給我們的幾個(gè)元注解
@Documented 表示是否將注解信息添加在java文檔中
@Retention 定義該注解的生命周期
@Target 表示該注解用于什么地方
@Inherited 定義該注釋和子類的關(guān)系
下面著重解釋后三個(gè)
-
@Retention
這個(gè)元注解表示他所修飾的注解的生命周期,即需要在什么級別保存該注解信息丰辣, Retention有一個(gè)屬性value撒强,是RetentionPolicy類型的禽捆,RetentionPolicy是一個(gè)枚舉 類型,這個(gè)枚舉決定了Retention注解應(yīng)該如何去保持飘哨。RetentionPolicy有以下三個(gè)值 **RetentionPolicy.SOURCE**:注解只保留在源文件胚想,當(dāng)Java文件編譯成class文件的時(shí)候,注解被遺棄芽隆; **RetentionPolicy.CLASS**:注解被保留到class文件浊服,但jvm加載class文件的時(shí)候被遺棄,這是默認(rèn)的生命周期胚吁; **RetentionPolicy.RUNTIME**:注解不僅被保存到class文件中牙躺,jvm加載class文件之后,仍然存在腕扶;
-
@Target
Target注解說明了他修飾的注解修飾的對象范圍孽拷,使用的時(shí)候類似于
@Target({ElementType.METHOD})
ElementType的取值以及含義如下圖
@Inherited
在注解上使用@Inherited 表示該注解會被子類繼承,注意半抱,僅針對類脓恕,成員屬性、方法并不受此注釋的影響窿侈。
自定義注解的例子:其中的@interface含義為聲明新的枚舉注解類型
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DemoAnnotions{
}
安卓中提供的幾個(gè)元注解
安卓在19.1版本開始引入了一個(gè)新的注解庫炼幔,也包含一些元注解供我們使用。
比如@IntDef & @StringDef,安卓中用@IntDef & @StringDef來代替枚舉的使用棉磨。
在日常開發(fā)中我們時(shí)常會有機(jī)會寫到枚舉江掩,但是枚舉是很耗內(nèi)存的学辱。每一個(gè)枚舉值都是一個(gè)單例對象,在使用它時(shí)會增加額外的內(nèi)存消耗乘瓤。
看一個(gè)@IntDef替代枚舉的例子:
@IntDef({DemoType.UGC, DemoType.PGC, DemoType.VIDEO, DemoType.IMAGE_TEXT, DemoType.PLAIN_TEXT})
@Retention(RetentionPolicy.SOURCE)
public @interface DemoType {
int UGC = 0;
int PGC = 1;
int VIDEO = 2;
int IMAGE_TEXT = 3;
int PLAIN_TEXT = 4;
}
定義@IntDef有兩種方式:
@IntDef({DemoType.UGC, DemoType.PGC, DemoType.VIDEO, DemoType.IMAGE_TEXT, DemoType.PLAIN_TEXT})
@IntDef(flag = true ,value = {DemoType.UGC, DemoType.PGC, DemoType.VIDEO, DemoType.IMAGE_TEXT, DemoType.PLAIN_TEXT})
在安卓中注解肯定不是只有替代枚舉這一個(gè)作用,事實(shí)上我們可以用注解實(shí)現(xiàn)非常多的功能策泣。比如我們常用的ButtterKnife中就有很多各種功能的注解衙傀。讓注解實(shí)現(xiàn)一個(gè)特定的功能就要說到反射了。
反射
-
反射的定義
Java反射機(jī)制是指在運(yùn)行狀態(tài)中萨咕,對于任意一個(gè)類统抬,都能知道這個(gè)類的所有屬性和方法。對于任何一個(gè)對象扰才,都能夠調(diào)用它的任何一個(gè)方法和屬性鲤嫡。這樣動態(tài)獲取新的以及動態(tài)調(diào)用對象方法的功能就叫做反射掉房。在Java中的反射機(jī)制,被稱為Reflection金麸。它允許運(yùn)行中的Java程序?qū)ψ陨磉M(jìn)行檢查,并能直接操作程序的內(nèi)部屬性或方法簿盅。Reflection機(jī)制允許程序在正在執(zhí)行的過程中挥下,利用Reflection APIs取得任何已知名稱的類的內(nèi)部信息揍魂,包括:package、 type parameters棚瘟、 superclass现斋、 implemented interfaces、 inner classes偎蘸、 outer classes庄蹋、 fields、 constructors迷雪、 methods蔓肯、 modifiers等,并可以在執(zhí)行的過程中振乏,動態(tài)生成Instances蔗包、變更fields內(nèi)容或喚起methods。
-
安卓中反射作用于注解
這里我們實(shí)現(xiàn)一個(gè)小功能來說明反射怎么作用于注解慧邮。
我們首先確定目標(biāo)调限,我們實(shí)現(xiàn)一個(gè)類似于ButterKnife中綁定view的功能,即使用注解代替findViewById的功能误澳。第一步先定義注解:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.CLASS) public @interface MyBindView { int value(); }
第二步寫注解解釋器
public void injects(AppCompatActivity activity) {
Class<? extends AppCompatActivity> clazz = activity.getClass();
Field[] fields = clazz.getFields();
if (fields != null && fields.length > 0) {
for (Field field : fields) {
//判斷字段是否標(biāo)注MyBindView
MyBindView myBindView = field.getAnnotation(MyBindView.class);
if (myBindView != null) {
//反射訪問私有成員耻矮,必須加上這句
View view = activity.findViewById(myBindView.value());
if (view != null) {
try {
field.setAccessible(true);
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
使用的時(shí)候如下:
injects(this);
@MyBindView(R.id.account_feedback_btn)
View feedbackBtn;
這樣就類似ButterKnife的@bindView功能了。