美文网首页android源码、开源框架解析
动态代理实现控件点击事件注入

动态代理实现控件点击事件注入

作者: 昊空_6f4f | 来源:发表于2020-07-19 12:10 被阅读0次

    概述

    本文主要分享基于动态代理实现控件点击事件注入。

    实现思路:

    • 自定义EventType注解标记需要点击事件类型
    • 自定义OnClick、OnLongClick注解标记点击、长按事件
    • 扫描页面中的注解,判断该注解是否被EventType注解标记
    • 获取EventType注解的事件类型通过动态代理创建对应的事件代理对象
    • 查找被OnClick、OnLongClick标示的控件并通过反射注入事件代理对象完成事件注入

    自定义EventType、OnClick、OnLongClick注解

    //这是一个元注解:即可以用在注解之上的注解
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface EventType {
    
        Class listenerType();
    
        String listenerSetter();
    
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @EventType(listenerType = View.OnClickListener.class,listenerSetter = "setOnClickListener")
    public @interface OnClick {
    
        int []value();
    
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @EventType(listenerType = View.OnLongClickListener.class,listenerSetter = "setOnLongClickListener")
    public @interface OnLongClick {
    
        int []value();
    
    }
    
    

    动态代理实现点击事件注入

    关键代码如下:

     public static void injectEvent(final MainActivity activity) {
    
            //注意:反射是基于Class
            Class<? extends MainActivity> activityClass = activity.getClass();
            //获取所有的方法
            Method[] declaredMethods = activityClass.getDeclaredMethods();
    
            for (final Method declaredMethod : declaredMethods) {
                //获取方法声明的注解数组,Annotation是所有注解的父接口
                Annotation[] annotations = declaredMethod.getAnnotations();
    
                for (Annotation annotation : annotations) {//OnClick、OnLongClick等
    
                    //获取注解类型
                    Class<? extends Annotation> annotationType = annotation.annotationType();
                    //A.isAnnotationPresent(B.class)即注释B是否在此A上
                    if (annotationType.isAnnotationPresent(EventType.class)) {
    
                        //获取EventType注解
                        EventType eventType = annotationType.getAnnotation(EventType.class);
    
                        //获取EventType注解声明的参数
                        Class listenerType = eventType.listenerType();
                        String listenerSetter = eventType.listenerSetter();
    
                        try {
    
                            Method valueMethod = annotationType.getDeclaredMethod("value");
                            //获取控件Id数组
                            int[] ids = (int[]) valueMethod.invoke(annotation);
    
                            declaredMethod.setAccessible(true);
    
                            //创建事件回调动态代理类,省去判断onClick、onLongClick
                            Object proxyInstance = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, new InvocationHandler() {
                                //动态代理回调方法
                                @Override
                                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                    return declaredMethod.invoke(activity, args);
                                }
                            });
    
                            for (int id : ids) {
                                //查处所有Id对应的控件
                                View view = activity.findViewById(id);
    
                                //获取指定的点击方法如:setOnClickListener、setOnLongClickListener
                                Method setMethod = view.getClass().getMethod(listenerSetter,listenerType);
                                //反射调用控件的setOnClickListener、setOnLongClickListener方法,进而调用到代理类的方法
                                setMethod.invoke(view, proxyInstance);
                            }
    
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } 
    

    页面注入

    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "fmt";
    
        @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.e(TAG, "click: 按钮1");
                    break;
                case R.id.btn2:
                    Log.e(TAG, "click: 按钮2");
                    break;
            }
        }
    
    
        @OnLongClick({R.id.btn1, R.id.btn2})
        public boolean longClick(View view) {
            switch (view.getId()) {
                case R.id.btn1:
                    Log.e(TAG, "longClick: 按钮1");
                    break;
                case R.id.btn2:
                    Log.e(TAG, "longClick: 按钮2");
                    break;
            }
            return false;
        }
    }
    

    完整代码实现

    百度链接

    密码:9ln0

    相关文章

      网友评论

        本文标题:动态代理实现控件点击事件注入

        本文链接:https://www.haomeiwen.com/subject/bqplkktx.html