自定義註解實現findViewById、onClick

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導入項目中使用了。

 

完。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章