EventBus 撸代码

作者: SeptemberWei | 来源:发表于2019-05-17 17:04 被阅读0次

    之前一直在用EventBus来做应用内的消息发送,但由于现在项目的开发环境不允许使用外网,因此很多第三方库都不能使用,因此自己学习并撸了一套低配的EventBus在此写下来记录一下。

    话不多说直接上代码

    EventBus主类,主要用于注册方法、发送数据。

    /**
     * @author wilson
     * @since 2019年03月17日22:58:24
     */
    public class EventBus {
        private final String TAG = getClass().getName();
        private static volatile EventBus instance;
    
        private HashMap<Object, List<SubscribleMethod>> methodCache;
    
        private Handler handler;
    
        private ExecutorService cacheExecutorService;
    
        private EventBus() {
            methodCache = new HashMap<>();
            handler = new Handler();
            cacheExecutorService = Executors.newCachedThreadPool();
        }
    
    
        public static EventBus getDefault() {
            if (instance == null) {
                synchronized (EventBus.class) {
                    if (instance == null) {
                        instance = new EventBus();
                    }
                }
            }
            return instance;
        }
    
    
        /**
         * 注册需要监听的class
         *
         * @param object
         */
        public void regist(Object object) {
            synchronized (EventBus.class) {
                List<SubscribleMethod> list = methodCache.get(object);
                if (list == null) {
                    list = findSubscribleMethods(object);
                    methodCache.put(object, list);
                }
            }
        }
    
        /**
         * 将class内带有Subscribe注解的方法及参数添加到缓存集合中
         *
         * @param object
         * @return
         */
        private List<SubscribleMethod> findSubscribleMethods(Object object) {
            List<SubscribleMethod> list = new ArrayList<>();
            Class<?> claz = object.getClass();
            Method[] declaredMethods = claz.getDeclaredMethods();
            while (claz != null) {
                String name = claz.getName();
                if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
                    break;
                }
                for (Method method : declaredMethods) {
                    Subscribe annotation = method.getAnnotation(Subscribe.class);
    
                    if (annotation != null) {
                        Class<?>[] parameterTypes = method.getParameterTypes();
                        if (parameterTypes.length != 1) {
                            Log.e(TAG, "eventbus 只能处理一个参数");
                        }
                        ThreadModel threadModel = annotation.threadMode();
    
                        SubscribleMethod subscribleMethod = new SubscribleMethod(method, threadModel, parameterTypes[0]);
                        list.add(subscribleMethod);
                    }
                }
                claz = claz.getSuperclass();
            }
    
            return list;
        }
    
        /**
         * 发送数据
         *
         * @param param
         */
        public void post(final Object param) {
            Set<Object> set = methodCache.keySet();
            Iterator<Object> iterator = set.iterator();
            while (iterator.hasNext()) {
                final Object obj = iterator.next();
                List<SubscribleMethod> list = methodCache.get(obj);
                for (final SubscribleMethod method : list) {
                    if (method.getParam().isAssignableFrom(param.getClass())) {
                        switch (method.getmThreadModel()) {
                            case Main:
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    invoke(method, obj, param);
                                } else {
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, obj, param);
                                        }
                                    });
                                }
                                break;
    
                            case Background:
                                //主到子
                                cacheExecutorService.execute(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(method, obj, param);
                                    }
                                });
                                break;
                        }
                    }
                }
            }
        }
    
        /**
         * 调用注册进来的带有Subscribe注解的方法
         *
         * @param subscribleMethod 注解方法对象
         * @param obj              claz
         * @param param            参数
         */
        private void invoke(SubscribleMethod subscribleMethod, Object obj, Object param) {
            Method method1 = subscribleMethod.getmMethod();
            try {
                method1.invoke(obj, param);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    在EventBus这个类的一些变量

        //用于存放注册的方法
        private HashMap<Object, List<SubscribleMethod>> methodCache;
        //发送数据到主线程
        private Handler handler;
        //发送数据到子线程
        private ExecutorService cacheExecutorService;
    

    regist方法,该方法用于注册需要监听的类(Activity,Fragment,Object等等)

    /**
         * 注册需要监听的class
         *
         * @param object
         */
        public void regist(Object object) {
            synchronized (EventBus.class) {
                List<SubscribleMethod> list = methodCache.get(object);
                if (list == null) {
                    list = findSubscribleMethods(object);
                    methodCache.put(object, list);
                }
            }
        }
    

    findSubscribleMethods方法,该方法主要用于将我们在类里面写的自定义方法

      /**
         * 将class内带有Subscribe注解的方法及参数添加到缓存集合中
         *
         * @param object
         * @return
         */
        private List<SubscribleMethod> findSubscribleMethods(Object object) {
            List<SubscribleMethod> list = new ArrayList<>();
            Class<?> claz = object.getClass();
            //获取当前类的所有方法
            Method[] declaredMethods = claz.getDeclaredMethods();
            while (claz != null) {
                //获取当前类的名字,如果是系统方法,就不在继续找注册的方法,因为我们不能把我们自定义的注解写到系统API里
                String name = claz.getName();
                if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
                    break;
                }
                for (Method method : declaredMethods) {
                    //获取我们写的Subscribe注解
                    Subscribe annotation = method.getAnnotation(Subscribe.class);
    
                    if (annotation != null) {
                        Class<?>[] parameterTypes = method.getParameterTypes();
                        if (parameterTypes.length != 1) {
                            Log.e(TAG, "eventbus 只能处理一个参数");
                        }
                        ThreadModel threadModel = annotation.threadMode();
    
                        SubscribleMethod subscribleMethod = new SubscribleMethod(method, threadModel, parameterTypes[0]);
    
                        //把注解方法对象添加到list中
                        list.add(subscribleMethod);
                    }
                }
                claz = claz.getSuperclass();
            }
    
            return list;
        }
    

    post 方法,方法数据到订阅的方法,其中threadMode定义了线程的切换

    /**
         * 发送数据
         *
         * @param param
         */
        public void post(final Object param) {
            Set<Object> set = methodCache.keySet();
            Iterator<Object> iterator = set.iterator();
            while (iterator.hasNext()) {
                final Object obj = iterator.next();
                List<SubscribleMethod> list = methodCache.get(obj);
                for (final SubscribleMethod method : list) {
                    if (method.getParam().isAssignableFrom(param.getClass())) {
                        switch (method.getmThreadModel()) {
                            case Main:
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    invoke(method, obj, param);
                                } else {
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, obj, param);
                                        }
                                    });
                                }
                                break;
    
                            case Background:
                                //主到子
                                cacheExecutorService.execute(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(method, obj, param);
                                    }
                                });
                                break;
                        }
                    }
                }
            }
        }
    
    

    上面方法中的invoke方法,reflect方式调用方法

    /**
         * 调用注册进来的带有Subscribe注解的方法
         *
         * @param subscribleMethod 注解方法对象
         * @param obj              claz
         * @param param            参数
         */
        private void invoke(SubscribleMethod subscribleMethod, Object obj, Object param) {
            Method method1 = subscribleMethod.getmMethod();
            try {
                method1.invoke(obj, param);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    

    ThreadModel就是一个简单的枚举类,用于切换子主线程

    public enum ThreadModel {
        Main, Background
    }
    

    自定义注解Subscribe类,该注解作用于方法上,在需要订阅的方法上直接添加该注解即可与原版EventBus使用方式一样

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Subscribe {
    
        ThreadModel threadMode() default ThreadModel.Main;
    }
    
    

    SubscribleMethod 就是一个普通的java bean

    public class SubscribleMethod {
        private Method mMethod;
        private ThreadModel mThreadModel;
        private Class<?> param;
    
    
        public Method getmMethod() {
            return mMethod;
        }
    
        public void setmMethod(Method mMethod) {
            this.mMethod = mMethod;
        }
    
        public ThreadModel getmThreadModel() {
            return mThreadModel;
        }
    
        public void setmThreadModel(ThreadModel mThreadModel) {
            this.mThreadModel = mThreadModel;
        }
    
        public Class<?> getParam() {
            return param;
        }
    
        public void setParam(Class<?> param) {
            this.param = param;
        }
    
        public SubscribleMethod(Method mMethod, ThreadModel mThreadModel, Class<?> param) {
            this.mMethod = mMethod;
            this.mThreadModel = mThreadModel;
            this.param = param;
    
        }
    }
    

    最后就是具体使用了,具体使用与原版的一模一样,只不过这个版本的Eventbus工具,没有像官方的支持粘性事件等等,主要还是为了满足现有项目的一些小小需求而做的。

    My github:

    相关文章

      网友评论

        本文标题:EventBus 撸代码

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