findViewById註解
實現效果:
只要在需要註解的Activity中聲明開啓,就能夠對字段綁定註解:像這樣:
@BindView(R.id.recycler)
private RecyclerView recyclerView;
@BindView(R.id.rg)
private RadioGroup radioGroup;
@BindView(R.id.tv)
private RadioGroup textView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
MyTool.init(this);
}
開始實現:
1、定義一個註解接口,然後在它上面聲明該註解用於字段,並且在程序編譯時保留該註解:
@Target({ElementType.FIELD}) //聲明該註解用於字段
@Retention(RetentionPolicy.RUNTIME) //跑起來時用
public @interface BindView{
int value(); //註解傳入的參數爲int類型
}
說明一下:
@Retention:註解的保留位置
@Retention(RetentionPolicy.SOURCE) //註解僅存在於源碼中,在class字節碼文件中不包含
@Retention(RetentionPolicy.CLASS) // 默認的保留策略,註解會在class字節碼文件中存在,但運行時無法獲得
@Retention(RetentionPolicy.RUNTIME) // 註解會在class字節碼文件中存在,在運行時可以通過反射獲取到
@Target:註解的作用目標
@Target(ElementType.TYPE) //接口、類、枚舉
@Target(ElementType.FIELD) //字段、枚舉的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法參數
@Target(ElementType.CONSTRUCTOR) //構造函數
@Target(ElementType.LOCAL_VARIABLE)//局部變量
@Target(ElementType.ANNOTATION_TYPE)//註解
@Target(ElementType.PACKAGE) ///包
2、對註解做反射完成想要的效果:
public class MyTool {
public MyTool() {
}
public static void init(Activity activity) {
try {
bindView(activity); //調用下面這個方法
} catch (IllegalAccessException var2) {
var2.printStackTrace();
} catch (IllegalArgumentException var3) {
var3.printStackTrace();
}
}
private static void bindView(Activity activity) throws IllegalAccessException, IllegalArgumentException {
Class clazz = activity.getClass(); //獲取當前Activity的類對象
Field[] declaredFields = clazz.getDeclaredFields(); //獲取這個類對象裏面所有的字段(數組集合)
for(int i = 0; i < declaredFields.length; ++i) { //遍歷這個數組
Field field = declaredFields[i]; //拿到單個字段
BindView bind = (BindView)field.getAnnotation(BindView.class); //拿到字段上面的BindView註解
if (bind != null) { //如果有BindView註解的話
int value = bind.value(); //獲取註解裏面的int值,也就是我們要的id
View findViewById = activity.findViewById(value); //找到這個View
field.setAccessible(true); //取消Java的權限控制檢查
field.set(activity, findViewById); //把該字段和view聯繫起來
}
}
}
}
說的很清楚了,至此,我們的findViewById的註解BindView就可以用了
接下來是對onClick點擊事件的綁定做註解
實現效果:
@ClickView(R.id.btn)
public void click(View v){
//do something
}
實現原理和字段綁定差不多:
開始實現:
1、聲明註解接口,並且指明是對方法做註解,傳入的參數也是int類型:
@Target({ElementType.METHOD}) //對方法做註解
@Retention(RetentionPolicy.RUNTIME)
public @interface ClickView {
int value();
}
2、獲取有該註解的方法進行綁定OnClick事件(和剛剛的MyTool寫在一起吧,整一個MyTool類如下):
public class MyTool{
public MyTool() {
}
public static void init(Activity activity) {
try {
bindView(activity);
bindClickEvent(activity);
} catch (IllegalAccessException var2) {
var2.printStackTrace();
} catch (IllegalArgumentException var3) {
var3.printStackTrace();
}
}
private static void bindView(Activity activity) throws IllegalAccessException, IllegalArgumentException {
Class clazz = activity.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
for(int i = 0; i < declaredFields.length; ++i) {
Field field = declaredFields[i];
BindView bind = (BindView)field.getAnnotation(BindView.class);
if (bind != null) {
int value = bind.value();
View findViewById = activity.findViewById(value);
field.setAccessible(true);
field.set(activity, findViewById);
}
}
}
private static void bindClickEvent(final Activity activity) {
Class clazz = activity.getClass();
Method[] declaredMethods = clazz.getDeclaredMethods(); //獲取到這個類的所有方法
for(int i = 0; i < declaredMethods.length; ++i) { //遍歷
final Method method = declaredMethods[i];
ClickView clickView = (ClickView)method.getAnnotation(ClickView.class); //獲取方法上面爲ClickView的註解
if (clickView != null) {
int value = clickView.value(); //拿參數:獲取到view的id
final View findViewById = activity.findViewById(value); //找到這個view
findViewById.setOnClickListener(new OnClickListener() { //給view設置點擊事件
public void onClick(View arg0) {
method.setAccessible(true); //別忘記了這個,才能拿到method下面的私有屬性
method.invoke(activity, findViewById); //該方法和這個view建立點擊事件的聯繫
}
});
}
}
}
}
最後,就可以把這個類和兩個註解接口打包成lib的jar導入項目中使用了。
完。