美文网首页
手写实现一个属于自己的EventBus

手写实现一个属于自己的EventBus

作者: 傅晨明 | 来源:发表于2020-11-17 16:01 被阅读0次

    生活案例

    image.png

    把Boss直聘比作EventBus。

    Boss直聘中维护一个总表,键是企业,值是该企业需要招聘的岗位列表,这个概念很重要,一定要搞清楚。

    对应到EventBus:

    • 总表:名为METHOD_CACHE的Map,
    • 企业:Activity的Class,
    • 岗位列表:List<SubscriberMethod>
    • 岗位:SubscriberMethod,也就是我们定义的接收方法的信息

    岗位 SubscriberMethod :

    /**
     * 职位
     */
    public class SubscriberMethod {
    
        //职位要做什么事情
        private Method method;
        //室内还是室外
        private ThreadMode threadMode;
        //工作岗位类型
        private Class<?> eventType;
    
        public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode) {
            this.method = method;
            this.threadMode = threadMode;
            this.eventType = eventType;
        }
    
        public Method getMethod() {
            return method;
        }
    
        public ThreadMode getThreadMode() {
            return threadMode;
        }
    
        public Class<?> getEventType() {
            return eventType;
        }
    }
    
        @Subscribe(threadMode = ThreadMode.MAIN)
        public void onMessageEvent(MyBusEvent event) {
            Log.i(TAG,"onMessageEvent接收到数据 =  " + event.message);
        }
    
    • method对应的是onMessageEvent
    • eventType对应的是MyBusEvent
      这两个对应关系也很重要,要搞清楚。

    METHOD_CACHE的定义如下:

    //总表:METHOD_CACHE
    //Class<?>对应阿里巴巴,List对应阿里巴巴中的所有职位
    private Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new HashMap<>();
    

    注册:将该企业到Boss直聘上注册填写岗位信息

    EventBus.getDefault().register(this);
    

    发送事件:求职者搜索岗位

    EventBus.getDefault().post( new MyBusEvent("fujunyang"));
    

    简单总结:

    • 总表:名为METHOD_CACHE的Map,
    • 企业:Activity的Class,
    • 岗位列表:List<SubscriberMethod>
    • 岗位:SubscriberMethod,

    注册:一个注册register,就是将该企业的所有岗位,添加到总表中。
    总表(METHOD_CACHE)的键是企业(Activity),值是该企业所有岗位(List<SubscriberMethod>)。

    发送事件:循环总表,在某个循环中,找出该企业对应的所有岗位。再循环所有岗位,找到求职者搜索的岗位是否和该企业所有岗位匹配。如果匹配就通过反射调用方法(method是onMessageEvent,参数是具体的Activity和MyBusEvent)

    获取EventBus对象

    使用单例,直接复用了EventBus的源代码

    public class EventBus {
        public static String TAG = "EventBus";
    
        static volatile EventBus defaultInstance;
        public static EventBus getDefault() {
            if (defaultInstance == null) {
                synchronized (EventBus.class) {
                    if (defaultInstance == null) {
                        defaultInstance = new EventBus();
                    }
                }
            }
            return defaultInstance;
        }
    

    注册

    EventBus通过如下实现注册

        @Override
        protected void onStart() {
            super.onStart();
            EventBus.getDefault().register(this);
        }
    

    注册的具体实现如下:

        public void register(Object subscriber) {
            Class<?> subscriberClass = subscriber.getClass();
            List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
            //如果不为空,说明阿里巴巴注册过,不需要再次注册
            if (subscriberMethods == null) {
                //如何寻找能够接收事件的方法??通过注解
                subscriberMethods = getSubscriberMethods(subscriber);
                METHOD_CACHE.put(subscriberClass, subscriberMethods);
            }
        }
    

    通过企业(Activity的Class)作为键,去总表METHOD_CACHE中获取所有该企业的职位subscriberMethods。

    如果subscriberMethods为null,说明该企业还没有注册过,我们才去注册。如果注册过了,就不再注册。

        private List<SubscriberMethod> getSubscriberMethods(Object subscriber) {
            List<SubscriberMethod> subscriberMethods = new ArrayList<>();
            Class clazz = subscriber.getClass();
            //getDeclaredMethod获取的是类自身声明的所有方法,包含public、protected、private方法
            Method[] methods = clazz.getDeclaredMethods();
            //需要将父类的注解也找出来,比如BaseActivity中可能也添加了注解
            while (clazz != null) {
                String clazzName = clazz.getName();
                //遇到系统类,直接跳出循环,不再去寻找
                if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") ||
                        clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) {
                    break;
                }
                for (Method method : methods) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation == null) {
                        continue;
                    }
                    //检测方法 是否符合规范
                    Class[] parameterTypes = method.getParameterTypes();
                    if (parameterTypes.length != 1) {
                        throw new RuntimeException("EventBus只能接收一个参数");
                    }
                    Class<?> eventType = parameterTypes[0];
                    ThreadMode threadMode = subscribeAnnotation.threadMode();
                    SubscriberMethod subscriberMethod = new SubscriberMethod(method, eventType, threadMode);
                    subscriberMethods.add(subscriberMethod);
                }
                clazz = clazz.getSuperclass();
            }
            return subscriberMethods;
        }
    

    发送事件

        //发送事件
        //事件对应岗位,假设现在event是android岗位
        public void post(Object event) {
            // 找哪个activity需要接收
            // 遍历总表,分别查看阿里和腾讯是否招android岗位
            Set<Class<?>> set = METHOD_CACHE.keySet();
            Iterator iterator = set.iterator();
            while (iterator.hasNext()) {
                //拿到公司,假设当前拿到的是阿里
                Class<?> subscriberClass = (Class<?>) iterator.next();
                //subscriberMethods是阿里的所有岗位集合
                List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
                for (SubscriberMethod subscriberMethod : subscriberMethods) {
                    //判断这个方法是否应该接收事件
                    //判断阿里的岗位中是否有招android岗位的
                    if (subscriberMethod.getEventType().isAssignableFrom(event.getClass())) {
    //                    invoke(subscriberMethod, subscriberClass, event);
                        Method method = subscriberMethod.getMethod();
                        try {
                            //通过反射调用方法
                            method.invoke(subscriberClass.newInstance(), event);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    

    在MainActivity中使用:

        @Subscribe(threadMode = ThreadMode.MAIN)
        public void onMessageEvent(MyBusEvent event) {
            Log.i(TAG,"onMessageEvent接收到数据 =  " + event.message);
    //        textView.setText(event.message);
    //        Toast.makeText(MainActivity.this, event.message, Toast.LENGTH_SHORT).show();
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            EventBus.getDefault().register(this);
        }
    

    最简单的说:就是通过注解,反射调用对应的方法


    相关文章

      网友评论

          本文标题:手写实现一个属于自己的EventBus

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