Eventbus概述

EventBus

EventBus可以分为3个部分:register,unregister和post

register

register又可以分为2部分:找出类里面注册的方法 和 把方法保存起来

找方法这部分,我画了个图:
这里写图片描述

方法的查找是由SubscriberMethodFinder这个类完成的
首先用到了缓存,METHOD_CACHE这个map,缓存了每个Class类型对应的注册方法列表,找到这些方法之后就会放到这个map里面,这样提高了查找效率

左边的findUsingInfo用到了编译时处理注解的技术,这个先不讲
右边就是传统的用反射去找
FindState这个类就是保存查找时用到的一些临时变量,这里FindState有一个缓存池,这样避免了频繁了创建和回收对象,这种思想值得学习的

往下看,eventBus会从当前这个类一直向上转型,也就是父类的注解方法也会去查找
从代码里可以看出,被注解的方法必须满足:
1,public或无访问修饰符
2,不能是static或abstract
3,参数为1个或没有,对于没有参数的情况,使用Void.class作为参数类型,这样就能统一处理

这个checkAdd当初我也看了很久,说说我的理解吧
我们考虑下面这种情况
这里写图片描述
子类有2个方法handleA和handleB,参数类型都是T
父类也有handleA方法
这种情况下,我们最终想要的method是子类的handleA和handleB
那当我们查找父类的时候,找到了父类的handleA方法,这个时候该怎么判断呢?
EventBus采用的方法是用一个map<String, Class>
String就是方法的签名,格式为:方法名>参数类型,例如handleA的方法签名就是:handleA>T
Class就是这个方法对应的类
由于是从子类开始找的,所以一开始这个string对应的是子类的class,后面查找父类的方法时,就检查这个映射,这样就可以保证拿到的是子类的方法了

当然这种情况可能发生频率不高,如果子类没有重写父类的方法,那生成方法签名就显得有点浪费
为了优化,EventBus又多弄了一个map<Class,Method>
Class指方法参数的类型,Method就是那个方法
当遇到一个类型对应多个方法的时候,才会使用方法签名这种方式来区分
大概就是这样

方法找完了,就要保存这些方法,调用的是EventBus的subscribe方法
使用map来保存,key是方法名字和参数类型,value就是Subscription的list (Subscription就是封装了注册者和method)
下面我们注意到,当把subscription放进list里面的时候,是按照注解的优先级来放的,这样就保证,已经按照优先级排好了,post的时候就方便了

下面还有sticky值得注意,从map<Class,Object>里根据方法的参数类型,取出object
可以推测,这个map保存了sticky事件,当注解标明sticky的方法注册的时候,就会检查这个map,如果取出的object不为null,那就会马上回调这个方法
那这个map什么时候会放东西进去呢?
我们看postSticky这个方法:

public void postSticky(Object event) {
        synchronized (stickyEvents) {
            stickyEvents.put(event.getClass(), event);
        }
        // Should be posted after it is putted, in case the subscriber wants to remove immediately
        post(event);
    }

在这里就会把event放进去
对于sticky的总结:如果要使用sticky,要用postSticky并且注册方法的注解要sticky = true

unregister

这个比较简单,就是从map里面找出注册者注册的方法,去除掉

post

主要的部分就是根据参数类型和方法名,找出对应的list,然后遍历反射调用方法
threadMode发挥作用的地方就是在postToSubscription方法里
这个方法就是根据threadMode,选择不同的Poster进行线程调度
Poster的结构图:
这里写图片描述
各个poster的流程:
这里写图片描述
这里写图片描述
这里写图片描述
这些我觉得有耐心看的话,也不难

我解释一下postingThreadState这个东西
这个类记录了当前正在执行的Subscription的信息
这个类的核心成员变量就是 boolean canceled
来看EventBus的这个方法

 public void cancelEventDelivery(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        if (!postingState.isPosting) {
            throw new EventBusException(
                    "This method may only be called from inside event handling methods on the posting thread");
        } else if (event == null) {
            throw new EventBusException("Event may not be null");
        } else if (postingState.event != event) {
            throw new EventBusException("Only the currently handled event may be aborted");
        } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) {
            throw new EventBusException(" event handlers may only abort the incoming event");
        }

        postingState.canceled = true;
    }

根据注解,这个方法应该在执行注册方法的途中调用,里面进行了很多条件检查,包括isPosting,event要相等,方法的threadmode注解必须为POSTING等等
最后,我们看到postingState.canceled = true,canceled变量变成了true
现在,我们再跳到iterateSubscriptions方法:

private boolean iterateSubscriptions(List<Subscription> subscriptionList, Object event, PostingThreadState postingState) {
        if(subscriptionList == null || subscriptionList.isEmpty()) return false;
        for (Subscription subscription : subscriptionList) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            if (aborted) {
                break;
            }
        }
        return true;
    }

注意try catch中那个 aborted = postingState.canceled
当canceled被置为true,aborted也为true,然后就会break,也就是说后面的subscription都不会执行了
这样实现阻断事件分发的功能


整体介绍到此结束了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值