自定义注解

++如果没有基础的同学必须先看我前面的java动态代理模式和java注解基础和java反射总结这几篇文章++

分析

注解起到一个规范作用&获取值得作用,那么值拿到之后就需要操作值,怎么操作呢?当然通过反射,所以接下来就看如何搞。我们从最熟悉的调用开始展开。

特殊说明
其中Class,Constructor,Field,Method,Package都实现了AnnotatedElement接口
该接口有如下几个方法为核心
//如果存在这样的注解,则返回该元素的指定类型的注解,否则为空。
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
//返回该程序元素上存在的所有注解。
Annotation[] getAnnotations()
//判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
boolean is AnnotationPresent(Class<?extends Annotation> annotationClass)
//返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
Annotation[] getDeclaredAnnotations()

实战

自定义注解的话我们需要用项目说话,话不多说

@ContentView(R.layout.activity_main)//布局注解
public class MainActivity extends AppCompatActivity {

    @ViewInject(R.id.btn)//控件注解
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Injector.inject(this);//注册注解
        btn.setText("改变按钮文本");
    }

    @OnClick({R.id.btn})//事件注解
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn:
                Toast.makeText(this, "Button OnClick", Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

ContentView

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

EventBase

/**
 * 事件注解的基本。如果你需要自行扩展各种事件,如点击事件、选项改变事件等,在该注解上加上此注解。
 */
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase {
    String listenerSetter();
    Class<?> listenerType();
    String callbackMethod();
}

OnClick

/**
 * 点击事件注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventBase(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class , callbackMethod = "onClick")
public @interface OnClick {
    int[] value();
}

注册器

/**
 * 注射器
 */
public class Injector {

    public static void inject(Activity activity) {
        try {
            injectContentView(activity);
            injectViewInject(activity);
            injectEvents(activity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static void injectContentView(Activity activity) {
        Class a = activity.getClass();
        if (!a.isAnnotationPresent(ContentView.class)) return;//判断ContentView注解是不是在该类上面
        ContentView contentView = (ContentView) a.getAnnotation(ContentView.class);
        int layoutId = contentView.value();//得到注解的值
        try {
            Method method = a.getMethod("setContentView", int.class);//得到setContentView方法
            method.setAccessible(true);//设置任意权限可用
            method.invoke(activity, layoutId);//执行
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static void injectViewInject(Activity activity) {
        Class a = activity.getClass();
        Field[] fields = a.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(ViewInject.class)) {
                ViewInject viewInject = field.getAnnotation(ViewInject.class);
                int viewId = viewInject.value();
                try {
                    Method method = a.getMethod("findViewById", int.class);
                    method.setAccessible(true);
                    Object resView = method.invoke(activity, viewId);//得到控件
                    field.setAccessible(true);
                    field.set(activity, resView);//设置给activity对象的值是findViewById得到的值相当于(Button btn = findViewById(R.id.btn);)
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private static void injectEvents(Activity activity) {
        Class a = activity.getClass();
        Method[] methods = a.getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(OnClick.class)) {
                OnClick onClick = method.getAnnotation(OnClick.class);
                int[] viewIds = onClick.value();//R.id.btn ...
                EventBase eventBase = onClick.annotationType().getAnnotation(EventBase.class);
                String methodName = eventBase.callbackMethod();//onClick
                String listenerSetter = eventBase.listenerSetter();//setOnClickListener
                Class<?> listenerType = eventBase.listenerType();//View.OnClickListener
                DynamicHandler handler = new DynamicHandler(activity);
                Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),new Class<?>[] { listenerType } /*listenerType.getInterfaces()*/, handler);//代理View.OnClickListener
                handler.addMethod(methodName, method);//将onClick添加到动态代理里面的容器
                for (int viewId : viewIds) {
                    try {
                        Method findViewByIdMethod = a.getMethod("findViewById", int.class);
                        findViewByIdMethod.setAccessible(true);
                        View view = (View) findViewByIdMethod.invoke(activity, viewId);//得到Button这个View
                        Method setEventListenerMethod = view.getClass().getMethod(listenerSetter, listenerType);//btn.setOnClickListener(View.OnClickListener listener);
                        setEventListenerMethod.setAccessible(true);
                        setEventListenerMethod.invoke(view, listener);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值