再學Android之EventBus源碼分析

EventBus源碼解析

市場上已經有不少分析EventBus的優秀文章,筆者在看了EventBus的源碼以後也是看了很多文章,在這裏表示感謝。 爲何要閱讀源碼?在我看來,當沒有一個大佬帶你前行的時候,源碼就是你的老師,看這些優秀的框架的源碼,的確能學到很多東西,這裏先總結一下,經過EventBus咱們能學到什麼java

  • DCL單例模式
  • Builder建造者模式
  • 享元模式
  • 反射
  • 線程池的使用

對於EventBus,這裏就不做太多介紹,相信每個作Android的應該都知道這個優秀的框架android

首先咱們先來看一下EventBus的常規用法: EventBus.getDefault().register(this); 接下來咱們來分佈看下都作了什麼。git

EventBus.getDefault()

咱們先來看一下,getDefault作了什麼github

static volatile EventBus defaultInstance;
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

/** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }
    
    public EventBus() {
        this(DEFAULT_BUILDER);
    }
    
    EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadSupport = builder.getMainThreadSupport();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        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;
    }
    
    
複製代碼

EventBus的實例構建採用了線程安全的DCL單例模式,而且實例defaultInstance加了volatile關鍵字。 真正的構建實例則是採用了builder模式。在EventBus的構造函數中有幾個須要咱們注意的地方:緩存

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    private final Map<Class<?>, Object> stickyEvents;
    private final ExecutorService executorService;
    
    
    EventBus(EventBusBuilder builder) {
        
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        executorService = builder.executorService;
        ...
    }
    
public class EventBusBuilder {
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;

    EventBusBuilder() {
    }
}
    
複製代碼

下面先簡單說下上面三個集合有什麼用:安全

  • subscriptionsByEventType 經過eventType去獲取Subsription,事件發送完以後,在尋找訂閱着的時候會用到
  • typesBySubscriber 經過Subscripber(訂閱者)去獲取全部的eventtype,在註冊和反註冊的時候會用到。
  • stickyEvents 粘性事件的集合

那麼Subscription是什麼? 是一個封裝了訂閱類和訂閱方法的一個對象bash

final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    }
    
複製代碼

那麼SubscriberMethod又是什麼? 是一個封裝了被@Subscribe註解的方法的一些信息app

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;
}

複製代碼

咱們再來看一下線程池建立比較有意思的地方: 默認的線程池是靜態的,而構建對象的時候則引用了默認的。這樣便巧妙的避開了線程池的沒必要要的建立。 下面再簡單介紹下Executors.newCachedThreadPool();這是java爲咱們提供的一個線程池,大小不受限,使用一個不存儲元素的阻塞隊列SynchronousQueue。固然若是咱們不滿意這種線程池的話,還能夠本身去配置框架

EventBusBuilder.class:

public EventBusBuilder executorService(ExecutorService executorService) {
        this.executorService = executorService;
        return this;
    }

複製代碼

到這裏getDefault的分析結束async

register

先來簡單看下源碼

/**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * <p/>
     * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
     * The {@link Subscribe} annotation also allows configuration like {@link
     * ThreadMode} and priority.
     */
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods =
        // 咱們要注意這個代碼 分析1
        subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
            // 訂閱 分析2
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
    
複製代碼

註釋中已經說了,當訂閱者不想接收事件的時候,必定要調用unregister。 咱們先來看下上面的分析1:

subscriberMethodFinder.findSubscriberMethods(subscriberClass);

subscriberClass咱們知道,那麼subscriberMethodFinder是什麼?在哪初始化的?看名字咱們大概知道這是幹嗎的,白話講就是:訂閱方法尋找器根據subscriberClass去尋找訂閱方法,也就是找到 訂閱類裏面全部的訂閱方法

EventBus(EventBusBuilder builder) {
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    }
    
複製代碼

上述代碼中的ignoreGeneratedIndex參數須要咱們注意,下面會分析

下面咱們來看下 subscriberMethodFinder.findSubscriberMethods(subscriberClass)的源碼

private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 先看緩存中有沒有該訂閱類的訂閱方法的集合,有的話就直接返回
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        // ignoreGeneratedIndex是有沒有使用APT,默認爲false
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        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;
        }
    }
複製代碼

上面代碼的邏輯不復雜,咱們一步一步分析。首先判斷緩存中有沒有該訂閱類的訂閱方法的集合,有的話直接返回,沒有的話根據ignoreGeneratedIndex字段判斷是使用APT去查找仍是使用反射的方式去查找,找到以後就存儲在緩存中,咱們看到,METHOD_CACHE使用的是ConcurrentHashMap線程安全的map類,既然ignoreGeneratedIndex參數默認爲false,那麼下面咱們來分析下findUsingInfo

findUsingInfo

在看這個源碼以前,咱們先來看下SubscriberMethodFinder的內部類FindState的源碼,看名字的意思是,查找狀態

FindStte

static class FindState {
        // 存儲訂閱方法的集合
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;
        Class<?> clazz;
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;

        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

        void recycle() {
            subscriberMethods.clear();
            anyMethodByEventType.clear();
            subscriberClassByMethodKey.clear();
            methodKeyBuilder.setLength(0);
            subscriberClass = null;
            clazz = null;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

        boolean checkAdd(Method method, Class<?> eventType) {
            // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
            // Usually a subscriber doesn't have methods listening to the same event type. Object existing = anyMethodByEventType.put(eventType, method); if (existing == null) { return true; } else { if (existing instanceof Method) { if (!checkAddWithMethodSignature((Method) existing, eventType)) { // Paranoia check throw new IllegalStateException(); } // Put any non-Method object to "consume" the existing Method anyMethodByEventType.put(eventType, this); } return checkAddWithMethodSignature(method, eventType); } } private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) { methodKeyBuilder.setLength(0); methodKeyBuilder.append(method.getName()); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); Class<?> methodClass = method.getDeclaringClass(); Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; } else { // Revert the put, old class is further down the class hierarchy subscriberClassByMethodKey.put(methodKey, methodClassOld); return false; } } // 向上查找他的父類 void moveToSuperclass() { if (skipSuperClasses) { clazz = null; } else { clazz = clazz.getSuperclass(); String clazzName = clazz.getName(); /** Skip system classes, this just degrades performance. */ if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { clazz = null; } } } } 複製代碼

看完源碼以後,咱們知道這個其實就是用於保存訂閱類的一些信息

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        // 採用享元模式,即對象複用,來構建FindState
        FindState findState = prepareFindState();
        // 初始化FindState的一些信息
        findState.initForSubscriber(subscriberClass);
        
        while (findState.clazz != null) {
            // 這裏默認是去APT生成的文件中去查找,這裏先不說
            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 {
            // 不使用APT的話會調用到這裏
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
    
SubscriberMethodFinder#prepareFindState:

//享元模式的應用,也就是對象的複用,防止大量的重複的實例話對象,減少內存,提升效率
    private static final int POOL_SIZE = 4;
    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
    
     private FindState prepareFindState() {
            synchronized (FIND_STATE_POOL) {
                for (int i = 0; i < POOL_SIZE; i++) {
                    FindState state = FIND_STATE_POOL[i];
                    if (state != null) {
                        FIND_STATE_POOL[i] = null;
                        return state;
                    }
                }
            }
            return new FindState();
        }
複製代碼

上面源碼中getSubscriberInfo其實就是去APT生成的文件中去查找訂閱的方法,可是使用APT的話須要我麼本身去配置,不配置的話默認確定返回null,那麼咱們先來分析一下:findUsingReflectionInSingleClass

看方法名字,餓哦們大概知道,利用反射去查找單獨的類,源碼很簡單,就是反射的常規用法,下面有註釋

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {
        //拿到操做符
            int modifiers = method.getModifiers();
            // 第一次過濾,操做符必須是public
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            // 拿到參數列表,進行第二次過濾,即參數的個數必須是1
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                // 獲得註解類
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                        // 獲得註解類上的線程模型
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            // 而後構建一個SubscriberMethod添加到findState.subscriberMethods的集合裏面
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException("@Subscribe method " + methodName +
                            "must have exactly 1 parameter but has " + parameterTypes.length);
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

複製代碼

咱們先簡單描述下上面方法的執行流程: 先反射獲取方法,而後根據各類條件進行判斷,知足的就添加到findState中,不知足的話就拋出異常

在回到findUsingInfo裏面,方法的最後調用了getMethodsAndRelease,咱們來簡單看下:

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
// 構建一個新的集合,將FindState中的訂閱方法(subscriberMethods)添加到新的集合裏面
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        // 回收資源
        findState.recycle();
        // 恢復對象池
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        // 將訂閱的方法的集合返回
        return subscriberMethods;
    }
複製代碼

咱們再回到findSubscriberMethods

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
        // 不實用APT的話,調用下面的方法
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
        // 上面已經分析過了
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        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;
        }
    }
複製代碼

咱們能夠看到不使用APT的話,調用的是findUsingReflection(subscriberClass)

private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
複製代碼

咱們看到,其實跟findUsingInfo的源碼差很少,只是沒有調用getSubscriberInfo,而是直接調用了findUsingReflectionInSingleClass

咱們在回到register方法

public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
複製代碼

拿到訂閱方法的集合以後,循環遍歷獲得subscriberMethod,而後調用subscribe(subscriber, subscriberMethod);

咱們先來簡單說下這個方法的做用

  • subscriptionsByEventType添加數據
  • typesBySubscriber添加數據
  • 處理事件的優先級
  • 處理粘性事件
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        // 從訂閱方法中獲得事件類型
        Class<?> eventType = subscriberMethod.eventType;
        // 構建Subscription
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        // 判斷subscriptionsByEventType有沒有,沒有的話構建出來,而後往裏面添加數據
        CopyOnWriteArrayList<Subscription> 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();
        // 處理事件的優先級
        //  這裏判斷subscriberMethod的優先級是不是大於集合中的subscriberMethod的優先級,若是是,把newSubscription插進去
     //  這也代表了subscription中priority大的在前,這樣在事件分發時就會先獲取。
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List<Class<?>> 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<Class>).
                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);
            }
        }
    }
複製代碼

接下來看一下unregister方法

public synchronized void unregister(Object subscriber) {
        // typesBySubscriber經過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());
        }
    }
    
    
    
複製代碼
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        // 根據事件類型拿到全部的訂閱
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                // 若是訂閱裏面的訂閱類等於當前訂閱類的話,移除
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }
複製代碼

接下來咱們看下post的源碼

post

咱們先來了解下EventBus的一個內部類PostingThreadState

final static class PostingThreadState {
        // 事件隊列
        final List<Object> eventQueue = new ArrayList<>(); 
        // 是否正在發送事件
        boolean isPosting;
        // 是否在祝線程
        boolean isMainThread;
        // 封裝了訂閱類和訂閱方法的對象
        Subscription subscription;
        // 事件
        Object event;
        // 是否取消
        boolean canceled;
    }
複製代碼

EventBus.post()

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
    
    
 public void post(Object event) {
 
        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;
            }
        }
    }
複製代碼

從上面的代碼中的判斷if (!postingState.isPosting)咱們能夠知道,不要在被訂閱的方法中往同一個線程中再次發送是事件,由於這樣是不處理的,因此咱們收不到這個事件

下面咱們來看一下postSingleEvent,發送單個事件,既然要發送事件,那麼確定要先找到訂閱這個事件的全部方法

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        // 是否找到訂閱方法
        boolean subscriptionFound = false;
        if (eventInheritance) {
        // 向上查找父類的全部被訂閱的放啊
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                // 重點看下這個方法
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }
複製代碼
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
// 經過subscriptionsByEventType,根據eventType拿到訂閱的集合
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
        
            for (Subscription subscription : subscriptions) {
                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;
        }
        return false;
    }
複製代碼

postToSubscription方法,主要作的就是線程的調度,主要利用Handler和前面介紹的線程池

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }
複製代碼

invokeSubscriber,利用反射調用訂閱方法

void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }
複製代碼

上面的整個流程分析下來,咱們大概看的出來,APT插件解決的只是EventBus.register的時候,方法的獲取不使用反射,可是在EventBus.post的時候,仍是經過反射去執行註解的方法

一直再說APT,那麼到底是什麼,該怎麼用

在3.0以後增長了註解處理器,在程序的編譯時候,就能夠根據註解生成相對應的代碼,相對於以前的直接經過運行時反射,大大提升了程序的運行效率 那咱們怎麼配置讓EventBus使用註解器生成的代碼呢?,SubscriberInfoIndex就是一個接口,而註解生成器生成的類也是繼承它 咱們先回到前面查找註冊方法的代碼

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        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);
    }
複製代碼

我麼前面分析的時候,直接走了else的分析,那麼if分之何時會執行呢?getSubscriberInfo(findState) != null

private SubscriberInfo getSubscriberInfo(FindState findState) {
       if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
           SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
           if (findState.clazz == superclassInfo.getSubscriberClass()) {
               return superclassInfo;
           }
       }
      //  判斷subscriberInfoIndexes 是否爲null,默認爲null,當咱們使用apt插件構建代碼 的時候,能夠手動的調用EventBusBuilder的addIndex,將subscriberInfoIndexes 進行賦值。
       if (subscriberInfoIndexes != null) {
           for (SubscriberInfoIndex index : subscriberInfoIndexes) {
               SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
               if (info != null) {
                   return info;
               }
           }
       }
       return null;
   }
   
複製代碼

那麼咱們該如何配置呢? 首先咱們在咱們的Activity裏面寫兩個訂閱方法

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true,priority = 10)
    public void getEventbusData(String string){
        Log.e("WFQ", "getEventbusData: " + string);
    }
    @Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = false,priority = 100)
    public void getEventbusData2(Integer integer){
        Log.e("WFQ", "getEventbusData2: " + integer);
    }
    
複製代碼

配置咱們的gradle

android {
    defaultConfig {

        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [eventBusIndex : applicationId + '.MyEventBusIndex']
            }
        }
    }
}



implementation 'org.greenrobot:eventbus:3.1.1'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
複製代碼

build項目,這個時候就會生成咱們的MyEventBusIndex,咱們一塊兒來看下

/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(com.wfq.demo0815.RxJavaMVP.demo.Demo1Activity.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("getEventbusData", String.class, ThreadMode.MAIN, 50, true),
            new SubscriberMethodInfo("getEventbusData2", Integer.class, ThreadMode.BACKGROUND, 100, false),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}
複製代碼

總結

EventBus.getDefault().register();

getdefault採用單例模式和建造者模式構建EventBus的實例,在構建實例的時候初始化了線程池,還初始化了幾個map,分別是subscriptionsByEventType:根據eventType去找到Subscription的集合,這個集合是線程安全的(COW), typesBySubsciber:根據訂閱類去找到eventType的集合類,其實這兩個是有關聯的,根據訂閱類去找到eventType的結合,遍歷集合,獲得eventType,而後根據eventType去subscriptionsByEventType中去找到Subscription的集合,遍歷集合的獲得subcription,這個是封裝了訂閱類和訂閱方法的一個對象,拿到訂閱方法以後咱們就能夠在發送事件時候去調用被訂閱的方法了。那麼這兩個集合都是在哪裏進行put的呢? 查找到訂閱方法以後調用了subscribe,在這個方法裏面去put的,咱們來看下怎麼查找訂閱方法的?

在register裏面,調用了subscriberMethodFinder.findSubscriberMethods(subscriberClass) 在這個方法裏,會先判斷緩存中有沒有這個類訂閱的方法的集合,有的話直接將集合返回,沒有的話會去判斷 ignoreGeneratedIndex參數,該參數表示是否忽略APT,默認爲false,也就是使用APT爲咱們生成的文件,調用 findUsingInfo(subscriberClass),在這個方法裏,會使用享元模式,實例話FindState,這個FindState就是用來保存訂閱類的一些信息,包括訂閱方法的集合等,而後會去調用getSubscriberInfo(findState),即去APT爲咱們生成的文件中去尋找註冊的方法,找打的話會把它添加在findstate的註冊方法的集合中去,找不到的話就使用反射去獲取這個訂閱類的全部註冊方法,而後將結果添加到findState的註冊方法的集合中去,最後調用getMethodsAndRelease, 在這個方法裏,會新建集合,獲取findState裏方法的集合,並釋放findState裏面的參數

EventBus.getDefault().post();

建立了一個ThreadLocal,PostingThreadState裏的變量: List eventQueue isPosting isMainThread Subscription event calceled

post的做用就是將事件添加到PostingThreadState的事件隊列中去,而後遍歷這個List,調用postSingleEvent, 既然要發送單個事件,就要知道訂閱這個事件的全部方法,經過subscriptionsByEventType拿到Subscriptions的COW,接着遍歷這個線程安全的類,拿到SUbscription,而後調用postToSubscrition,在這個方法裏進行了線程調度, 最終都會調用invokeSubscriber,在這裏經過反射調用方法

相關文章
相關標籤/搜索