Android使用注解和反射简单的实现ButterKnife

目的
使用注解代替setContentView(),findViewById(),onClick()和onLongClick()的点击事件
如图在这里插入图片描述一、实现setContentView()
1、先写个注解InjectLayout在这里插入图片描述(1)@interface:注解的写法(声明)
(2)@Target:目标(此注解作用在什么地方)一下是常用的几个
ElementType.TYPE:类名之上
ElementType.FIELD:属性字段之上(成员变量)
ElementType.METHOD:方法之上
ElementType.CONSTRUCTOR:构造函数
ElementType.LOCAL_VARIABLE:局部变量
ElementType.ANNOTATION_TYPE:注解之上(注解的注解 称为原注解(3)@Retention 注解在哪个阶段保留也就是可见
RetentionPolicy.SOURCE:源码阶段
RetentionPolicy.CLASS:在类文件时
RetentionPolicy.RUNTIME:运行时
(4)int value():int类型参数

以上先简单的介绍下注解的含义 下面开始撸码

首先创建个InjectManage注入管理类一个inject方法 外部调用此方法注入在这里插入图片描述思路
1)通过obj获取到Class对象

Class<?> clazz = obj.getClass();

2)通过Class对象获取到类注解

InjectLayout injectLayout = clazz.getAnnotation(InjectLayout.class);

3)判断当前类是否有注解(也就是区分Activity类和普通的Test类)

    3.1:如果injectLayout不为空就是有注解

4)如果有注解通过Class对象,反射获取到setContentView方法

Method setContentView = clazz.getMethod("setContentView", int.class);

getMethod()获取公共方法
getDeclaredMethod() 获取所有的包括公共 私有…方法

param1:方法名
param2:方法的参数类型

5)获取到注解参数

int value = injectLayout.value();

value相当于R.layout.activity_main

6)执行获取到的setContentView方法

setContentView.invoke(obj, value);
  1. 整体代码

在这里插入图片描述
二、实现findViewById()

1、写个注入控件View的注解InjectView

这里Target要改成FIELD,因为这是作用在属性之上的
我们在injectLayout方法下增加injectView方法
2、获取Class对象

Class<?> clazz = obj.getClass();

3、获取所有属性

Field[] fields = clazz.getDeclaredFields();

4、遍历属性,判断是否有InjectView注解

InjectView injectView = field.getAnnotation(InjectView.class);

5、通过反射获取到findViewById方法

Method findViewById = clazz.getMethod("findViewById", int.class);

6、获取参数 执行findViewById方法

int value = injectView.value();
View view = (View) findViewById.invoke(obj, value);

注意;到这里只是执行了findViewById方法 并没有给控件赋值
7、给空间赋值

 //因属性有私有的 这里设置为可访问课操作
 field.setAccessible(true);
 //给控件赋值
 field.set(obj, view);

8、完整方法代码
在这里插入图片描述三、onClick和onLongClick
直接上代码也就是以上两个的扩容
1、onClick注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
//这个注解为原注解 是作用在注解之上的 用来用来区分方法的注解
@InjectEvent(listenerSetting = "setOnClickListener", listenerType = View.OnClickListener.class,
        callBackMethod = "onClick")
public @interface OnClick {
    //点击事件 有可能有多个
    int[] value();
}

onLongClick注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@InjectEvent(listenerSetting = "setOnLongClickListener", listenerType = View.OnLongClickListener.class,
        callBackMethod = "onLongClick")
public @interface OnLongClick {
    int[] value();
}

InjectEvent原注解

@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectEvent {
    //事件三要素
    //方法名
    String listenerSetting();
    //参数类型
    Class listenerType();
    //回调方法
    String callBackMethod();
}

整体方法

private static void injectEvent(Object obj) {
        Class<?> clazz = obj.getClass();
        //获取所有方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            //获取所有注解
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation : annotations) {
                //获取注解对象的class
                Class<? extends Annotation> annotationType = annotation.annotationType();
                //获取InjectEvent注解对象
                InjectEvent injectEvent = annotationType.getAnnotation(InjectEvent.class);
                if (injectEvent != null) {
                    //获取参数
                    String listenerSetting = injectEvent.listenerSetting();
                    Class listenerType = injectEvent.listenerType();
                    String callBackMethod = injectEvent.callBackMethod();
                    ListenerHandler listenerHandler = new ListenerHandler(obj, method);
                    //动态代理
                    Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),
                            new Class[]{listenerType}, listenerHandler);
                    try {
                        //获取注解里value 相当于注解之上的所有Id
                        Method valueMethod = annotationType.getDeclaredMethod("value");
                        int[] ids = (int[]) valueMethod.invoke(annotation);
                        for (int id : ids) {
                            Method findViewById = clazz.getMethod("findViewById",int.class);
                            View btn = (View) findViewById.invoke(obj, id);
                            //setOnClickListener的method对象
                            Method setterMethod = btn.getClass().getMethod(listenerSetting, listenerType);
                            //btn.setOnClickListener
                            //第二个参数  new View.OnClickListener
                            setterMethod.invoke(btn, listener);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

动态代理

public class ListenerHandler implements InvocationHandler {

    private Object object;
    private Method mMethod;

    public ListenerHandler(Object object, Method method) {
        this.object = object;
        this.mMethod = method;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return mMethod.invoke(object, args);
    }
}

第一次写文章记录,写的不好还忘海涵~~~以后多多努力~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值