EventBus源码看一看,了解一下思路。

EventBus使用的是观察者模式,使用步骤主要分为三步:

1.订阅者注册
EventBus.getDefault().register(this);

2.发布者发布事件
EventBus.getDefault().post(event);

3.订阅者解除注册
EventBus.getDefault().unregister(this);


观看EventBus源码中,主要有两个Map十分重要:

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;

主要就是两个Map,剩余一个 stickyEvents 是粘性事件的Map,不管啦。

  • subscriptionsByEventType:
    该Map以EventType为key,Subscription数组为value,存储订阅者信息。暂且称之为注册Map。
  • typesBySubscriber:
    该Map以订阅者为key,EventType为value。主要用于解除注册使用。暂且称之为解注册Map

1.订阅者注册

    /**
     * 调用该方法注册
     */
    public void register(Object subscriber) {
        //1、获取订阅者的字节码文件
        Class<?> subscriberClass = subscriber.getClass();


        //2、获取订阅者里面所有的订阅方法(即使用了 @Subscribe 注解的方法)
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

        //3.将订阅者,订阅方法,EventType添加到两个Map中(即subscriptionsByEventType和typesBySubscriber)
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

主要来看看subscribe方法:

    /**
     * 必须在同步代码块中调用
     */
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;

        //将订阅者,订阅方法封装成一个类(Subscription)
        //Subscription只要在订阅者,订阅方法都相同的情况下才认为是相等的
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

        //以EventType为key,查找subscriptionsByEventType是否已经存在该Subscription。
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            //以EventType为key,Subscription列表为value,存储到map集合中。注意当前Subscription列表是一个为空
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            //禁止重复注册
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        //如果当前列表已经存在,添加当前Subscription到列表中
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        //将EventType列表为value,订阅者为key,存入到解注册Map中
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        //粘性事件相关处理
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

注册过程大概就是这样。注册过程中,实际上就是往两个Map中填充数据的过程。
步骤是这样的:

  1. 调用 EventBus#register()
  2. register方法首先调用 SubscriberMethodFinder#findSubscriberMethods() 方法,找到当前订阅者里面所有的订阅方法,也就是加了@Subscribe 注解的方法啦。然后返回一个SubscriberMethod的集合subscriberMethods。
  3. register 方法再去遍历subscriberMethods,然后集合中的每个元素都调用EventBus#subscribe() 方法,将subscriber,SubscriberMethod与EventType进行关联。

而对于 EventBus#subscribe() 方法重点说明一下,主要分为以下步骤:

  1. 将 Subscriber, SubscriberMethod 封装成一个 Subscription 类
  2. 根据 EventType 查找 subscriptionsByEventType ,得到一个 Subscription 的列表,然后查看列表中是否存在当前的 Subscription 实例,不存在就放入列表中,存在就报错呗
  3. 同理,根据 subscriber 为 key, 查找 typesBySubscriber ,得到一个EventType 的列表,然后查找该列表是否存在该 subscriber, 不存在就直接存入表中,存在就报错。

2.发布者发布事件

    /**
     * 发布者通过此方法发布事件
     */
    public void post(Object event) {
        //从ThreadLocal中取出PostingThreadState,该对象中主要包含一个事件队列(eventQueue),并添加事件到队列中
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                //依次遍历事件队列
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

主要就是先把发送的Event添加到队列中,然后开始遍历队列,调用postSingleEvent方法。
postSingleEvent就是进行一系列的处理,正常情况下就调用了postSingleEventForEventType方法。

postSingleEventForEventType方法主要作用就是根据Event,从注册Map中取出subscription列表,由前面的可以知道,subscription实际上就是subscriber与method封装而成的类。
所以,此时就知道了需要调用哪个类的哪个方法,接下来就是通过反射调用具体的方法咯。系统中调用的postToSubscription方法。
大致思路就是这样。

3.订阅者解除注册

    public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

实际上就是移除前面中两个Map中的Subscription。分为两步:

  1. 在typesBySubscriber中,根据subscriber找到该订阅者所有的订阅事件类型。即EventType列表
  2. 在subscriptionsByEventType,根据EventType列表,找到subcription列表,直接remove即可。

从解除注册就可以看到了,为啥需要两个Map去保存EventType,SubScriber,Method信息。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值