本篇不涉及任何源码,单纯讲一下它的流程,然后讲一下优缺点。

Eventbus 中有三个集合,这基本就是核心所在。

    private final Map, CopyOnWriteArrayList> subscriptionsByEventType;//第一个集合的存储的//key是数据类型的clazz //value 是一个Subscription集合,//Subscription对象是一个包装类,包含注册的时候传进去的对象 和对象中一个带 @Subscribe 注解的方法,很抽象 举例演示一下 

 

public class A {        @Subscribe (threadMode = ThreadMode.MAIN)    public void accept1(Person p){            }    @Subscribe (threadMode = ThreadMode.MAIN)    public void accept2(Person p){            }}public class B {        @Subscribe (threadMode = ThreadMode.MAIN)    public void accept3(Person p){            }    @Subscribe (threadMode = ThreadMode.MAIN)    public void accept4(Person p){            }}public class C {        @Subscribe (threadMode = ThreadMode.MAIN)    public void accept1(Student s){            }     @Subscribe (threadMode = ThreadMode.MAIN)    public void accept2(Student s){            }   }

1,当 A 类调用  EventBus.getDefault().register(this);进行注册之后 ,

subscriptionsByEventType集合长度为 1,第一个key是 Person.Class ,value 就是一个长度为2的CopyOnWriteArrayList对象,CopyOnWriteArrayList中

第一个Subscription 是A对象的实例和 A对象的 accept1方法封装成的 Subscription 对象,

第二个Subscription 是A对象的实例和 A对象的 accept2方法封装成的 Subscription  对象

2,当B类对象调用 EventBus.getDefault().register(this);进行注册之后 ,

subscriptionsByEventType集合长度为 1,第一个key是Person.Class ,value 就是一个长度为4的CopyOnWriteArrayList对象,CopyOnWriteArrayList中

第一个Subscription 是A对象的实例和 A对象的 accept1方法封装成的 Subscription 对象,

第二个Subscription 是A对象的实例和 A对象的 accept2方法封装成的 Subscription 对象,

第三个Subscription 是B对象的实例和 B对象的 accept3方法封装成的 Subscription  对象,

第四个Subscription 是B对象的实例和 B对象的 accept4方法封装成的 Subscription  对象,

3,当C类对象调用 EventBus.getDefault().register(this);进行注册之后 ,

subscriptionsByEventType集合长度为 2,

第一个key是 Person.Class ,第一个key对应的Value 就是一个长度为4的CopyOnWriteArrayList对象,

第一个CopyOnWriteArrayList对象中的四个对象《步骤2中的四个Subscription 》

第二个key是 Student.Class, 第二个key对应的value 是一个长度为 2的 CopyOnWriteArrayList 对象,

第二个CopyOnWriteArrayList对象中的两个个对象

第一个Subscription 是C对象的实例和 C对象的 accept1方法封装成的 Subscription 对象,

第一个Subscription 是C对象的实例和 C对象的 accept2方法封装成的 Subscription 对象,

在总结一下 ,

1,所有订阅的方法中,有多少参数类型,subscriptionsByEventType 的长度就是多少,每个参数类型 对应一个list集合。

2,该参数类型有多少个订阅的方法 ,对应的list集合长度就是多少,每一个Subscription  对象都是订阅的方法和方法所在的类的 实例。

这个集合的作用就是用来 分发事件用的,当发事件的时候,根据分发的事件类型的Clazz ,拿到对应订阅的方法的集合CopyOnWriteArrayList对象,然后逐一遍历进行分发,这也就是分发的原理。当然真正的流程没有这么简单,还涉及到了线程切换等等,这里不细说,主要介绍主流程。

伪代码

   public void register (Object subscriber){            Class<?> tagClass = tag.getClass();            List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(tagClass);//通过反射拿到所有方法,SubscriberMethod封装的方法的参数类型,线程类型,优先级,粘性            synchronized (this) {                //遍历所有方法                for (SubscriberMethod subscriberMethod : subscriberMethods) {                    //拿参数类型                    Class<?> eventType = subscriberMethod.eventType;                    //进行封装 Subscription 除了包含方法所有参数之外还有tag的引用                    Subscription newSubscription = new Subscription(tag, subscriberMethod);//根据参数类型去第一个集合中判断是否有当前集合,如果没有就创建新的集合,如果有就根据优先级把当前的订阅方法封装添加进去                    CopyOnWriteArrayList list = subscriptionsByEventType.get(eventType);                    if (list == null) {                        list = new CopyOnWriteArrayList<>();                        subscriptionsByEventType.put(eventType, subscriptions);                    } else {                        //这里根据优先级添加,我没有写。                        list.add(Subscription);                    }                }            }        }

 

 

 

第二个集合

 private final Map>> typesBySubscriber;//这个集合的作用主要解除注册用的 ,//key是注册时候的tag//vlaue 的值是一个参数类型Clazz集合。

当有类进行注册的时候,对第一个集合进行操作的同时,也会对第二个集合进行操作,(上边的流程)

1,当 A 类调用  EventBus.getDefault().register(this);进行注册之后 ,

typesBySubscriber集合长度为 1,第一个key的A对象 ,value 就是一个长度为2的List对象,

第一个Class是Person.Class,

第二个Class是Person.Class,

2,当B类对象调用 EventBus.getDefault().register(this);进行注册之后 ,

typesBySubscriber集合长度为 2,

第一个key的A对象 ,value 就是一个长度为2的List对象,

《步骤一中的list 》

第二个Key是B对象,Vlaue 就是一个长度为2的List对象,

第一个Class是Person.Class,

第二个Class是Person.Class,

3,当C类对象调用 EventBus.getDefault().register(this);进行注册之后 ,

typesBySubscriber集合长度为 3,

第一个key的A对象 ,value 就是一个长度为2的List对象,

《步骤一中的list 》

第二个Key是B对象,Vlaue 就是一个长度为2的List对象,

《步骤二中的list 》

第三个Key 是C对象,value 就是一个长度为2的List对象,

第一个Class是Student.Class,

第二个Class是Student.Class,

在总结一下 ,

1,有多少个对象订阅了,typesBySubscriber的长度就是多少,每个订阅对象对应一个list集合。

2,每个订阅的对象中有多少个订阅的方法,list的长度就是多少,源码就是遍历所有订阅的方法,list把每个方法的参数添加进去。

这个集合主要的作用是用来解除注册的,

解除注册的时候,首先拿到要解除注册对象的所有方法的参数class的集合,然后遍历这个class集合,遍历的时候 通过第一个集合拿到每一个class所有的订阅方法,这里拿到的也是一个集合CopyOnWriteArrayList ,在遍历这个集合,凡是Subscription中 持有的对象 和当前要解除的对象一样的情况下,就把当前Subscription对象 从CopyOnWriteArrayList当中移除。遍历完所有list 集合之后就成功的解除了当前对象所有的订阅,最后从typesBySubscriber 把 当前对象保留的集合移除

伪代码

        public synchronized void unregister(Object tag) {// 拿到当前对象所有的订阅方法            List> subscribedTypes = typesBySubscriber.get(tag);            if (subscribedTypes != null) {//遍历所有方法                for (Class<?> eventType : subscribedTypes) {//拿到每个参数类型的所有订阅                    List subscriptions = subscriptionsByEventType.get(eventType);                    if (subscriptions != null) {//遍历每个参数类型 所有订阅的方法合集                        int size = subscriptions.size();                        for (int i = 0; i < size; i++) {                            Subscription subscription = subscriptions.get(i);//如果订阅的方法 中tag的和当前解除的一样就移除                            if (subscription.subscriber == tag) {                                subscriptions.remove(i);                            }                        }                    }                }                typesBySubscriber.remove(subscriber);            }        }

 

第三个集合的作用 作为粘性分发的作用

    private final Map, Object> stickyEvents;//第三个集合是粘性分发//key是数据类型的clazz //value 是数据对象,

 现在说事件分发 只介绍两种正常分发 和粘性分发

第一种,正常分发

直接上伪代码

 public void post(Object event) {        Class<?> eventClass = event.getClass();        //从第一个集合中,通过参数类型按到需要分发所有方法的集合        CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventClass);        //遍历方法进行分发        if (subscriptions != null && !subscriptions.isEmpty()) {            for (Subscription subscription : subscriptions) {               //判断线程,切换线程的代码省略,简单说一下,四种类型                 // 第一种 POSTING 不做线程切换                // 第二种 MAIN 如果发送的不在主线程 通过handler 切换线程                // 第三种 BACKGROUND 如果不是主线程的就不进行线程切换,如果是主线程就进行线程切换,通过线程池进行切换                // 第四种  ASYNC ,无论在不在主线程,都进行线程切换,通过线程池切换                //反射调用方法,把事件发送出                subscription.subscriberMethod.method.invoke(subscription.tag, event);            }        }    }

 这就是正常分发流程。

第二种粘性分发,粘性分发的就是先分发,后注册也能收到消息,原理就在此,正常分发,然后把数据存起来。

1,粘性分发首先执行一边上边正常的流程。

2,利用第三个集合 把分发的数据保存起来

再讲前边注册的流程中 最后一步,

伪代码

public void register(Object  tag){  ............//第一个集合操作过程//第二个集合操作过程..........//判断是粘性事件   if (subscriberMethod.sticky) {        //拿到需要分发的数据对象 ,然后单独对当前订阅的方法进行分发        Object stickyEvent = stickyEvents.get(eventType);        subscriberMethod.invoke(tag, stickyEvent);    }}

 

最后简单串联一下逻辑:

注册的时候

1把当前对象所有注册方法放到第一个集合当中管理,为了分发 用。

2同事第二个集合保存的数据就是记录了那些对象注册了,用来解除注册。 

3如果是粘性事件 去第三个集合中寻找对应的数据类型和数据,然后直接进行分发。

发送事件的时候

1根据发送的事件类型找到所有需要发送对象的对应方法

解除注册的时候,

1通过第二个集合找到所有注册的方法,然后进行逐个判断进行解除注册。

 

最后说一下个人所认为的优缺点 

优点 :可以跨模块发送消息。原理就是动态注册动态发送

缺点 : 接受事件类型

1事件类型会定义很多

 

 

2不同模块的消息类型必须两个模块都能引用到才行

3不是流程式的代码,阅读性差。个人倾向于流程式的代码。

 

// 妈蛋复制出来这两个空行,结果我按删除键删不掉,索性吐槽一下它,作为一个用户,我觉得如果做不到让用户傻瓜式操作的都是有问题的(按删除键删除不掉),如果有谁知道 请留言给我怎么删除,谢谢 。

 

 

 

 

更多相关文章

  1. 安卓四大组件之——ContentProvider学习
  2. Android底部fragment互相跳转
  3. Android(安卓)extends和implements不同
  4. android 数据存储——SharedPreferences,有代码实现,简单易懂
  5. Android(安卓)壁纸设置_01
  6. html5开发全屏android软件
  7. Android(安卓)Matrix进阶方法详解
  8. android service与activity交互的方试
  9. Android(安卓)library projects cannot be launched解决方法

随机推荐

  1. Android 使用CountDownTimer实现倒计时
  2. Android基于Handler实现倒计时
  3. android安装后控件拖不动问题解答
  4. Android 中可重写的一些样式
  5. android Intent的一些用法
  6. Android 引入AspectJ的记录
  7. 安卓笔记:安卓控件属性大全
  8. Android样式的开发:drawable汇总篇
  9. [Android系列—] 1. Android 开发环境搭
  10. Android中TextView 行间距和段间距设置