【13】注解反射动态代理实现控件事件注入

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

注解反射动态代理实现控件事件注入

1.实现思路

(1)定义事件类型注解, 其属性值包含事件监听类,与监听事件方法名称。
(2)定义单击事件注解,其属性值为单击事件控件的id数组集合。
(3)定义单击长按事件注解,其属性值为单击长按事件控件的id数组集合。
(4)定义事件注解解析器,通过反射获取方法上所有的注解信息,解析注解信息获取监听事件的数据类型及设置监听事件的方法名称。
(5)通过动态代理生成事件监听注入的代理类对象,通过反射获取监听事件需要执行的方法并执行。

2.定义事件类型注解

@Target({ ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EventType {
    //注解属性,监听类
    Class listenerType();
    //注解属性,监听事件方法名称
    String listenerSetter();

}

3.定义单击,单击长按事件注解

@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@EventType(listenerType = View.OnClickListener.class,listenerSetter = "setOnClickListener")
public @interface OnClick{
    int[] value();
}
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@EventType(listenerType = View.OnLongClickListener.class,listenerSetter = "setOnLongClickListener")
public @interface OnLongClick {
    int[] value();
}

4.定义注解信息解析器

public class InjectUtils {

    /**
     * 利用反射、注解、动态代理为指定Activity类的控件注入事件
     */
    public static void injectEvent(Activity activity){

        Class<? extends Activity> activityClass = activity.getClass();
        Method[] declaredMethods = activityClass.getDeclaredMethods();

        for(Method method : declaredMethods){
            //1.获取方法上所有的注解信息
            Annotation[] annotations = method.getAnnotations();
            for(Annotation annotation : annotations){
                //1.1解析注解信息
                Class<? extends Annotation> annotationType =
                        annotation.annotationType();
                //1.2方法返回true,如果指定类型的注解存在于此元素上,否则返回false。
                if(annotationType.isAnnotationPresent(EventType.class)){
                    //1.2.1获取注解类信息
                    EventType eventType =
                            annotationType.getAnnotation(EventType.class);

                    //1.2.2获取监听事件类型
                    Class listenerType = eventType.listenerType();

                    //1.2.3获取设置监听事件的方法名称
                    String listenerSetter = eventType.listenerSetter();

                    try {
                        //1.2.4取得控件id
                        Method valueMethod = annotationType.getDeclaredMethod("value");
                        int[] viewIds = (int[]) valueMethod.invoke(annotation);

                        //1.2.5通过动态代理动态生成事件处理对象
                        method.setAccessible(true);
                        ListenerInvocationHandler<Activity> handler =
                                new ListenerInvocationHandler<>(activity,method);
                        Object listenerProxy =
                                Proxy.newProxyInstance(listenerType.getClassLoader(),
                                        new Class[]{listenerType},handler);

                        for(int viewId : viewIds){
                            //1.2.6.获取需要添加事件的控件
                            View view = activity.findViewById(viewId);
                            //1.2.7通过反射获取监听事件
                            Method setter =
                                    view.getClass().getMethod(listenerSetter,listenerType);
                            setter.invoke(view,listenerProxy);
                        }
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    /**
     * 事件回调之所以使用泛型T,是因为控件类型有可能是自定义的View.
     * @param <T>
     */
    static class ListenerInvocationHandler<T> implements InvocationHandler{

        private Method method;
        private T target;

        public ListenerInvocationHandler(T target,Method method) {
            this.method = method;
            this.target = target;
        }

        @Override
        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
            //解决Expected to unbox a 'boolean' primitive type but was returned null异常
            if (boolean.class == method.getReturnType()) {
                this.method.invoke(target, objects);
                return true;
            }else {
                return this.method.invoke(target, objects);
            }
        }
    }

}

5.使用

/**
 * 通过注解、反射、依赖注入实现控件事件的自动注入
 */
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        InjectUtils.injectEvent(this);
    }

    @OnClick({R.id.btn1,R.id.btn2})
    public void click(View view){
        switch (view.getId()){
        case R.id.btn1:
            Log.i(TAG,"click:按钮1");
            break;
        case R.id.btn2:
            Log.i(TAG,"click:按钮2");
            break;
        }
    }

    @OnLongClick({R.id.btn1,R.id.btn2})
    public void longClick(View view){
        switch (view.getId()){
        case R.id.btn1:
            Log.i(TAG,"longClick:按钮1");
            break;
        case R.id.btn2:
            Log.i(TAG,"longClick:按钮2");
            break;
        }
    }
}

6.打赏鼓励

感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!

6.1微信打赏

在这里插入图片描述

6.2支付宝打赏

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值