文章目录
前言
一、获取 Activity 中的所有方法
二、获取方法上的注解
三、获取注解上的注解
四、通过注解属性获取相关事件信息
前言
Android 依赖注入的核心就是通过反射获取 类 / 方法 / 字段 上的注解 , 以及注解属性 ; 在 Activity 基类中 , 获取该注解 以及 注解属性 , 进行相关操作 ;
在博客 【IOC 控制反转】Android 事件依赖注入 ( 事件三要素 | 修饰注解的注解 | 事件依赖注入步骤 ) 中 , 定义了 2 22 个注解 ,
第一个是方法上的注解 , 用于修饰方法 ;
第二个是修饰注解的注解 , 该注解用于配置注入的方法 ( 事件监听方法 | 监听器类型 | 监听器回调方法 ) ;
事件依赖注入比较复杂 , 涉及到动态代理 , 本博客分析 【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入代码示例 ) 事件依赖注入的详细步骤 ;
本博客的核心是 : 使用动态代理 , 创建 View.OnClickListener 或 View.OnLongClickListener 或 View.onTouchListener 等接口的动态代理类 ;
拦截相应的 onClick , onLongClick , onTouch 方法 , 执行自己的方法 , 其它方法正常执行 ;
一、获取 Activity 中的所有方法
通过反射获取 Activity 类 , 然后调用 Class 的 getDeclaredMethods 方法 , 获取 Activity 中的所有方法 ;
// 获取 Class 字节码对象 Class<? extends Activity> clazz = activity.getClass(); // 获取所有方法 Method[] methods = clazz.getDeclaredMethods();
二、获取方法上的注解
获取方法的所有注解 , 获取的是 @OnClick({R.id.textView}) // 事件注入 注解 ;
调用 Method 方法的 getDeclaredAnnotations 方法 , 获取方法上的注解数组 ;
// 循环遍历类的方法 for (int i = 0; i < methods.length; i ++) { // 获取方法的所有注解 Annotation[] annotations = methods[i].getDeclaredAnnotations(); }
三、获取注解上的注解
遍历上个步骤获取的注解数组 , 每个注解上可能有多个修饰注解的注解 , 如下注解是 OnClick 上的 3 33 个注解 ;
@Target(ElementType.METHOD) // 该注解作用于方法上 @Retention(RetentionPolicy.RUNTIME) // 注解保留到运行时 @EventBase( listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class, callbackMethod = "onClick") public @interface OnClick { int[] value(); // 接收 int 类型数组 }
调用 annotationType 方法 , 获取注解的类型 , 只处理 @EventBase 注解 ;
// 遍历所有的注解 for (int j = 0; j < annotations.length; j ++) { // 获取注解类型 Class<? extends Annotation> annotationType = annotations[j].annotationType(); // 获取 @EventBase 注解 EventBase eventBase = annotationType.getAnnotation(EventBase.class); if (eventBase == null) { // 如果没有获取到 EventBase 注解 , 执行下一次循环 continue; } }
四、通过注解属性获取相关事件信息
最终目的是进行如下设置 :
textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } });
需要获取 textView 组件 , 可以在注解中获取 @OnClick({R.id.textView}) 组件 ID , 根据 ID 获取组件 ;
获取并执行 View 组件的 setOnClickListener 方法 , 通过反射获取该方法 ;
创建 View.OnClickListener 接口实现类 , 并实现 onClick 方法 , 这里特别注意 , 必须使用代理拦截该方法 , 替换成自己的方法 , 即在 MainActivity 中使用 @OnClick({R.id.textView}) 注解修饰的方法 ;
如果使用静态代理 , 则只能创建固定的 View.OnClickListener 接口的静态代理类 , 无法实现为组件设置长按事件 , 触摸事件 ;
因此这里使用动态代理实现 , 使用动态代理 , 创建 View.OnClickListener 或 View.OnLongClickListener 或 View.onTouchListener 等接口的动态代理类 ;
在 @EventBase 注解中配置事件的三要素 , 设置事件监听的方法 , 监听器类型 , 事件触发回调方法 ;
package kim.hsl.ioc_lib; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义注解 * 用于注解上的注解 * 用于依赖注入视图 */ @Target(ElementType.ANNOTATION_TYPE) // 该注解作用于注解上 @Retention(RetentionPolicy.RUNTIME) // 注解保留到运行时 public @interface EventBase { /** * 设置事件监听的方法 * @return */ String listenerSetter(); /** * 设置监听器类型 * @return */ Class<?> listenerType(); /** * 事件触发后的回调方法 * @return */ String callbackMethod(); }
获取注解中的事件三要素 :
// 点击事件 View.setOnClickListener String listenerSetter = eventBase.listenerSetter(); // 监听器类型 View.OnClickListener Class<?> listenerType = eventBase.listenerType(); // 事件触发回调方法 public void onClick(View v) String callbackMethod = eventBase.callbackMethod();
获取 要拦截的方法 以及 要注入的方法 ,
要拦截的方法是事件监听器的方法 , 要注入的方法是用户在 MainActivity 中使用 @OnClick 注解修饰的方法 ;
最后将这两个方法放在 Map 集合中 ;
// 拦截 callbackMethod 方法 , 执行 method[i] 方法 // 这个 method[i] 方法就是在 MainActivity 中用户自定义方法 // 被 OnClick 注解修饰的方法 // 将其封装到 Map 集合中 Map<String, Method> methodMap = new HashMap<>(); methodMap.put(callbackMethod, methods[i]