本博客是一個純技術(shù)交流博客招盲,寫出來的文章是幫大家解決一些問題溃肪,或讓大家有個參考和思路,更多技術(shù)分享請關(guān)注http://blog.36dr.net痹栖,有任何問題可與我郵件dr.kalen@yahoo.com。
前言
Android默認(rèn)提供Annotation框架同時網(wǎng)絡(luò)也沖刺著各種Android Annotation框架瞭空,諸如此類框架很多结耀,但是用過之后使用都比較復(fù)雜留夜,同時還有一些無法避免的bug。如在Android開發(fā)時經(jīng)常會遇到獲得界面中的View使用方法findViewById特別是在Adapter中需要對所有使用的組件變量賦值图甜,每次調(diào)用findViewById就顯得多余的開發(fā)碍粥,若采用注解則會方便開發(fā),精簡代碼的結(jié)構(gòu)和提示代碼閱讀性黑毅,當(dāng)然由于Annotation是反射機制設(shè)置變量值嚼摩,則在性能上會相對于普通方式差,在此硬件比拼的時代矿瘦,此性能幾乎可以忽略枕面。
原理和自定義
以前言中提到Android開發(fā)多次調(diào)用findViewById方法的困惑,我們通過自定義Annotation來解決此問題缚去。如下:
- 定義注解類:
@Target(ElementType.FIELD)//表示用在字段上
@Retention(RetentionPolicy.RUNTIME)//表示在生命周期是運行時
public @interface ViewInject {
int value() default 0; //返回注解中的信息
}
- 定義一個BaseActivity作為需要注解的基類潮秘,用于實現(xiàn)注解的功能(反射注入數(shù)據(jù))
public abstract class BaseActivity extends FragmentActivity {
/**
* get content view layout id
*
* @return
*/
public abstract int getLayoutId();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
autoInjectAllField();
}
/**
* 解析注解
*/
public void autoInjectAllField() {
try {
Class<?> clazz = this.getClass();
Field[] fields = clazz.getDeclaredFields();//獲得Activity中聲明的字段
for (Field field : fields) {
// 查看這個字段是否有我們自定義的注解類標(biāo)志的
if (field.isAnnotationPresent(ViewInject.class)) {
ViewInject inject = field.getAnnotation(ViewInject.class);
int id = inject.value();
if (id > 0) {
field.setAccessible(true);
field.set(this, this.findViewById(id));//給我們要找的字段設(shè)置值
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
- 注解使用
public class TestActivity extends BaseActivity {
@ViewInject(R.id.claim_statement)
private WebView mWebView;
@Override
public int getLayoutId() {
// TODO Auto-generated method stub
return R.layout.activity_claim;
}
}
詳細(xì)說明
系統(tǒng)中方法經(jīng)常會使用@Override和@Deprecated注解,我們看看系統(tǒng)注解如何定義:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
我們發(fā)現(xiàn)這兩個注解用到了其他注解@Target,@Retention,@Documented易结;這些注解稱之為元注解枕荞。
- @Target用于標(biāo)明注解用于的地方,它的值是一個枚舉值:
- CONSTRUCTOR:用于描述構(gòu)造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部變量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述參數(shù)
- TYPE:用于描述類搞动、接口(包括注解類型) 或enum聲明
- @Retention用于描述注解的生命周期即在什么情況有效躏精,它的值:
- SOURCE:在源文件中有效(即源文件保留編譯時忽略)
- CLASS:在class文件中有效(即class保留JVM忽略)
- RUNTIME:在運行時有效(即運行時保留)
- @Documented表明這個注解應(yīng)該被javadoc工具記錄。
因此當(dāng)我們定義的注解中:
@Target(ElementType.FIELD)//表示用在字段上
@Retention(RetentionPolicy.RUNTIME)//表示在生命周期是運行時
public @interface ViewInject {
int value() default 0; //返回注解中的信息
String name() default "default name"
}
就很好解釋了鹦肿,ViewInject注解是用于變量并且運行時有效矗烛,用于獲得注解中的內(nèi)容,內(nèi)容信息為int并且默認(rèn)為0.
注解類中方法value()表示獲取注解中默認(rèn)文字比如@ViewInject(R.id.name)獲取的R.id.name的值箩溃,如果是name或則其他方法瞭吃,則表示需要在注解中使用屬性才能獲取。及獲取@ViewInject(name="name")中的name屬性值涣旨。
由此虱而,我們可以根據(jù)自己喜好,自己的功能需要开泽,自定義合適項目的注解和注解的解析方式牡拇。
Android 注解請學(xué)習(xí)“Android Annotation”框架。