Java高级

Java--Annotation之旅 ( Runtime反射篇

2020-11-11  本文已影响0人  初夏的雪

相信经过前面两篇文章的学习,我们对Java Annotation 有了一定的掌握了。仔细的同学注意到了,我们自定义的注解的保留级别是source ,那么APT技术就是注解source级别的重要应用场景之一,其次该级别的应用场景是IDE可以根据注解来进行语法检查,例如:@IdRes ,@IntDef 等注解,详细用法可以去找度娘。

我们今天要学习的是注解另外一个应用场景(即Runtime保留级别)--反射的使用。

关于反射后面会有详细的文章来介绍,这里就不展开介绍了。

接下来我们就直接开撸:

我们还是接着使用上两篇中的自定义的注解,也可以到github上下载学习Demo

public class InjectUtils {

    /*
     * TODO 反射绑定view
     */
    public static void injectAnnotation(final Activity activity) {
        Class<? extends Activity> aClass = activity.getClass();

        /*
         * TODO 获取所有的自己的fields,不包括父类
         */
        Field[] declaredFields = aClass.getDeclaredFields();
        for (int i = 0; i < declaredFields.length; i++) {
            //遍历所有的field
            Field field = declaredFields[i];
            if (field.isAnnotationPresent(BindView.class)) {
                //找到使用BindView注解的属性,并取出对应的注解
                BindView annotation = field.getAnnotation(BindView.class);
                if (annotation != null) {
                    //获取到注解的参数值
                    int viewId = annotation.viewId();
                    //找到Id对应的视图
                    View view = activity.findViewById(viewId);

                    //设置field是可以访问的,否则则不能操作
                    field.setAccessible(true);
                    try {
                        //将找到的视图赋值给field
                        field.set(activity, view);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        /*
        * TODO 获取该类所有的方法,不包括父类
        */
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (int i = 0; i < declaredMethods.length; i++) {
            final Method declaredMethod = declaredMethods[i];
            if (declaredMethod.isAnnotationPresent(ViewOnClick.class)) {
                ViewOnClick annotation = declaredMethod.getAnnotation(ViewOnClick.class);
                if (annotation != null) {
                    final int[] viewIds = annotation.viewId();
                    for (int i1 = 0; i1 < viewIds.length; i1++) {
                        final int finalI = i1;
                        activity.findViewById(viewIds[i1]).setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                try {
                                    //反射方法的调用使用invoke
                                    declaredMethod.invoke(activity, viewIds[finalI]);
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        });

                    }
                }
            }
        }
    }
}

上述代码几乎对每一句都进行了注释,大家可以看到,method 和Field的处理逻辑基础一致,所以下面处理method上的注解的注释可以对照上半部分。

特别说明:

  1. 由于每一次都会对所有的field ,或 method 进行遍历,这样会比较影响效率,这也是反射存在的一个问题
  2. 反射在注解中使用,那么注解必须是Runtime保留级别,笔者粗心使用上一篇中的SOURCE级别注解,未修改,则一直无法成功
  3. getDeclaredFields() 和getFields()两个方法的区别,前者是返回当前类的所有的成员变量,不包括父类;后者则返回当前类及其父类的(public)所有的成员变量(含static),那么如何区分父类的成员变量呢,可以调用superClass()的getDeclaredFields()方法获取。
    同理:getDeclaredMethods()和getMethods()是一个道理

简单使用:

 @BindView(viewId = R.id.inject_btn)
    Button mInjectBtn;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_inject);
        InjectUtils.injectAnnotation(this);
    }


    @ViewOnClick(viewId = R.id.inject_btn)
    public void onClick(@IdRes int viewId) {
        if (viewId == R.id.inject_btn) {
            Toast.makeText(this, mInjectBtn.getText().toString(), Toast.LENGTH_SHORT).show();
        }
    }

其实和注解处理器的使用是一样的,只是InjectUtils.injectAnnotation(this);换成反射工具的调用了。

怎么样,反射来处理注解是不是很简单?以上是注解应用场景--运行时反射解析。那么注解保留级别是CLASS时的应用场景又是什么呢,我们下一篇来学习。

上一篇 下一篇

猜你喜欢

热点阅读