EventBus笔记--源码--注册

会了基本的EventBus的使用后 , 是不是感觉乍一看和广播有点像 ? 接下来我们八一八源码, 瞅一眼它的内部实现
提示 : 不要被庞大的代码量吓到 , 慢慢来其实也不复杂

EventBus笔记--源码--注册_第1张图片

EventBus -- 基本使用
EventBus源码 -- 注册
EventBus源码 -- 发送消息
EventBus源码 -- 注销


EventBus的注册

EventBus.getDefalt().regist(this) 这一句话就完成了EventBus的注册.

  • 首先查看getDefalt()方法:
 public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

这里使用了双重校验的单例模式 , 获取到了一个EventBus的实例 . 在初始化有用到了new EventBus()这个方法, 我们再来看看这个构造函数 .

public EventBus() {
        this(DEFAULT_BUILDER);
    }

再来看看有参构造函数

EventBus(EventBusBuilder builder) {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }

这些都是各种对象的实例化.

  • 拿到实例之后, 使用regist(this)进行注册
public void register(Object subscriber) {
        Class subscriberClass = subscriber.getClass(); //首先获取到订阅者的Class对象 , 就是注册的位置.
        // 接下来在方法中遍历, 获取订阅方法<点进去>
        List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); 
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                // 进行订阅 , 将订阅方法和对应的订阅者保存起来 <最后看这个方法>
                subscribe(subscriber, subscriberMethod); 
            }
        }
    }

接下来看findSubscriberMethods方法 , 该方法从订阅类中获取到了所有的订阅信息 .

List findSubscriberMethods(Class subscriberClass) {
        // 以订阅者为key , 在缓存中读取订阅者方法
        List subscriberMethods = METHOD_CACHE.get(subscriberClass); 
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        // 缓存中没有方法时
        if (ignoreGeneratedIndex) {
            // 通过反射来获取
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            //通过注解获取 , 一般使用这种方法 <点进去> 
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        // 如果集合仍然为空 . 说明在订阅者里面没有写订阅方法 , 或者订阅方法不是public , 这也说明了上文中 , 
        // 订阅方法必须为public
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            // 获取到方法后 , 首先添加到缓存中, 再返回
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

在看如何通过注解来获取: findUsingInfo

private List findUsingInfo(Class subscriberClass) {
        // 准备一个查找状态池 , 用"池"来优化查找速率
        FindState findState = prepareFindState();
        // 对查找状态池初始化
        findState.initForSubscriber(subscriberClass);

        //默认为null
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                // 获取订阅的方法 , <点进去看>
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

获取订阅方法findUsingReflectionInSingleClass
这个方法就不贴代码了(毕竟不太懂注解的东西) , 大致过程就是:

  1. 首先通过反射订阅者所有的方法 , 如果没有方法就获取全部方法 , 并保存在方法数组中 .
  2. 然后遍历获取到的方法, 过滤掉非公有的方法后, 获取公有方法的参数类型 , 参数长度必须为1
  3. 检验是否含有@Subscribe的注解
  4. 校验该方法是否已添加到总线方法集合中, 如没有 , 就通过方法查找池添加到订阅方法集合中
    所以在这里现总结一下订阅方法的要求 :

公有 , 参数长度为1 , 有@Subscribe的注解


至此 , 在注册的过程中就获取到了订阅者的所有方法, 然后我们在看订阅方法和订阅者的订阅过程 : subscribe(subscriber, subscriberMethod);

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        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;
            }
        }

        List> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List).
                Set, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry, 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);
            }
        }
    }

不在代码上一一标注了 . 从上到下大致的来说一下子.

  1. 传进来的参数 , 第一个是订阅者 , 第二个是订阅方法 , 可以再返回去看一下 , 这个方法是for循环中的 , 针对每一个订阅方法都进行一次订阅 .
  2. 获取订阅方法的事件类型(参数类型) , 根据订阅的事件类型获取所有的订阅者
  3. 将订阅者添加到subscriptionsByEventType集合中 , 这个集合存放的是事件类型和订阅方法的映射
  4. 接下来针对订阅方法的优先级(priority)进行排序
  5. 获取该订阅者中的所有订阅方法的事件类型 , 添加到订阅事件集合中.
  6. 粘性事件的处理(还没看)

总结

其实EventBus的注册就是

  1. 通过反射获取到所有的订阅方法
  2. 将订阅者添加到EventBus总的事件订阅者集合中
  3. 将订阅者所有的订阅事件类型添加到typesBySubscriber中

再搞清楚两个集合的作用:

  • subscriptionsByEventType: 事件类型与订阅者的映射
  • typesBySubscriber : 订阅者和订阅类型的映射

吐槽一下: map的命名方式真反人类

你可能感兴趣的:(EventBus笔记--源码--注册)