在項目開發(fā)中,想要獲取布局中相應(yīng)的控件都是通過findViewById來實現(xiàn)的,當(dāng)然還可以使用一些第三方的注解框架,像XUtils没龙、butterKnidnife等;本人的話不太喜歡使用這些第三方的,可能不太習(xí)慣還有就是改動不太方便硬纤,所有在開發(fā)中都是在BaseActivity封裝一下解滓,
@SuppressWarnings("unchecked")
protected <T extends View> T ID(int id) {
return (T) super.findViewById(id);
}
然后在子類中使用,這樣其實只不過不用每次findViewById的時候進(jìn)行強(qiáng)轉(zhuǎn)筝家,后面在學(xué)習(xí)和開發(fā)過程中洼裤,看到一位大牛自己寫了一個IOC的注解,跟著也學(xué)了下溪王,感覺還不錯腮鞍,它是通過反射和注解的方式來實現(xiàn),并且可以根據(jù)自己的需要很方便的進(jìn)行添加和修改莹菱,根據(jù)需要移国,新建了三個注解類,ViewById道伟、OnClick迹缀、CheckNet,ViewById是控件皱卓,OnClick是點擊事件裹芝,CheckNet是檢測網(wǎng)絡(luò);
ViewById注解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewById {
int value();
}
@Target代表的是注解的位置娜汁,有四中類型:
ElementType.FIELD 代表的是在屬性上
ElementType.METHOD 代表的是在方法上
ElementType.TYPE 代表的是在類上
ElementType.CONSTRUCTOR 代表的是在構(gòu)造方法上
@Retention表示什么什么時候生效嫂易,用三種類型;
RetentionPolicy.RUNTIME 運行時生效
RetentionPolicy.CLASS 編譯時生效
RetentionPolicy.SOURCE 源碼資源
OnClick和CheckNet的實現(xiàn)都是一樣的掐禁,OnClick改下@Target的位置就可以了怜械,CheckNet的話不用傳遞參數(shù);
通過反射和注解的方式傅事,調(diào)用的還是android系統(tǒng)的findViewById方法缕允,在寫反射方法之前提供一個findViewById的幫助類;
public class ViewFinder {
private Activity mActivity;
private View mView;
public ViewFinder(Activity activity) {
this.mActivity = activity;
}
public ViewFinder(View view) {
this.mView = view;
}
public View findViewById(int viewId) {
return mActivity != null ? mActivity.findViewById(viewId) : mView.findViewById(viewId);
}
}
該類提供了針對Activity 和View 兩種構(gòu)造方法蹭越,接下來在ViewUtils類中來實現(xiàn)具體的方法就可以了障本;ViewUtils類中也提供了三種方式的構(gòu)造方法;
public static void inject(Activity activity) {
inject(new ViewFinder(activity), activity);
}
public static void inject(View view) {
inject(new ViewFinder(view), view);
}
public static void inject(View view, Object object) {
inject(new ViewFinder(view), object);
}
public static void inject(ViewFinder finder, Object object) {
injectFiled(finder, object);
injectEvent(finder, object);
}
先根據(jù)傳入進(jìn)來的Object類响鹃,通過反射獲取到該類所有的屬性驾霜,
//獲取類中所有的屬性
Class<?> clazz = object.getClass();
//獲取所有屬性包括公有和私有
Field[] fields = clazz.getDeclaredFields();
循環(huán)遍歷該屬性數(shù)組,得到Object類的每一個屬性买置,判斷該屬性上面是否與ViewById的注解一致粪糙,如果一致就通過set();方法設(shè)置;
//獲取ViewById中的value值
for (Field field : fields) {
ViewById viewById = field.getAnnotation(ViewById.class);
if (viewById != null) {
//獲取注解里面的id值
int value = viewById.value();
//findViewById找到view
View view = finder.findViewById(value);
if (view != null) {
//能夠修飾所有修飾符
field.setAccessible(true);
//動態(tài)注入找到的view
try {
field.set(object, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
在遍歷獲取每個屬性的時候要field.setAccessible(true);設(shè)置為true允許訪問Object類的私有屬性忿项,這樣findViewById就ok了蓉冈,點擊事件的話跟findViewById是一樣的將屬性換成方法就可以了城舞;在使用的時候首先要將ViewUtils類進(jìn)行初始化;
@ViewById(R.id.tv)
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewUtils.inject(this);
tv.setText("IOCTest");
}
這樣就實現(xiàn)了寞酿,運行下家夺,效果如下:
源碼地址:http://pan.baidu.com/s/1nv2Zw6l