通常情况下,我们在写控件的时候都会调用findViewById的方法来获取View实例,并且还要强制转换(Android studio 3.0之后不需要),非常繁琐,当然了市面上也有ButterKinfe这样的的第三方库来辅助开发者提高开发效率,如果我们自己去实现这样的框架其实也很简单,几个步骤就可以完成,不过首先要对注解有比较深刻的理解。

第一步:定义注解

代码如下:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LcsBindView {
    int value();
}

主要来说定义注解分三步,@inteface标明当前是注解类,@号不能漏掉,否则变成了接口了

@Target注解

我们注解作用的目标,这里是ElementType.FIELD,也就是作用于字段的,还有其他的修饰如下:

1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述字段
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

@Retention注解

注解的运行级别

RetentionPolicy的类型有以下几种

   1.SOURCE:在源文件中有效(即源文件保留)
 2.CLASS:在class文件中有效(即class保留)
 3.RUNTIME:在运行时有效(即运行时保留)

看解释应该明白,他们的级别是:1<=2<=3

至此注解就定义完成了。

第二步骤:绑定关联

顾名思义,简单的定义是使用不了的,我们要把控件和注解关联起来,才能正常使用

线上代码:

//核心方法
public static void bindViews(Activity activity) {
    Class<? extends Activity> activityClass = activity.getClass();//获取activity的class
    Field[] fields = activityClass.getDeclaredFields();//获取activity的字段
    //遍历所有的字段
    for (Field field : fields) {
        //获取该字段的注解
        LcsBindView lcsBindView = field.getAnnotation(LcsBindView.class);
        //!=null 说明该字段有注解并且是指定的注解
        if (lcsBindView != null) {
            //获取到注解总传入的数值value
            int viewId = lcsBindView.value();
            if(viewId != -1){
                try {
                    //获取到activity中findViewById的方法
                    Method findViewByIdMethod = activityClass.getMethod("findViewById", int.class);
                    try {
                        //执行findViewById方法
                        Object resView = findViewByIdMethod.invoke(activity, viewId);
                        //允许通过反射访问私有变量
                        field.setAccessible(true);
                        //把字段的值设置该view的实例
                        field.set(activity, resView);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

先看里面的注释,大概可以理解我们的关联步骤,主要是先获取到activity的class实例,之后在获取到类中的所有字段,之后再进行遍历、获取字段的注解类,如果是当前我们需要的注解类,我们再获取到activity中的findViewById的方法,通过反射去执行这个方法,并且把获取到value也就是控件Id传进去,那么我们的控件就被实例化了,然后再把返回的object的对象设置到该对应字段上面,这样在activity中用此字段就不会发生空指针了,整个过程就结束了,activity中的使用如下:

@LcsBindView(R.id.tv_test)
private TextView tvTest;
BindViewUtils.bindViews(this);
tvTest.setText("我是通过 @LcsBindView 找到的,哈哈哈~");

先进行注解修饰,再进行注解关联,就可以使用了,是不是很简单呢:D

05-16 07:44