EventBus源碼分析

瞭解EventBus基本用法之前,要先了解一下它的三要素:

  • Event:事件。可以是任意類型的對象
  • Subscriber:事件訂閱者。3.0以後可隨意取名,添加@Subscribe註解並指定現場模型即可(默認POSTING)
  • Publisher:事件發佈者。可在任意線程、位置發送事件,直接調用post方法

關於EventBus的4種線程模型:

  • POSTING(默認):在同一個線程中發佈、接收事件。該模型中需儘量避免執行耗時操作,因爲其會阻塞事件傳遞,甚至ANR
  • MAIN:在UI線程處理事件。處理事件太長會導致ANR
  • BACKGROUND:若UI線程發佈,就在新線程處理;若在子線程發佈,就在當前線程處理。事件的處理函數中,禁止進行UI更新操作
  • SYNC:無論在哪個線程發佈,都會在新線程中處理。事件的處理函數中,禁止進行UI更新操作

一、基本用法

自定義事件類:

/**
 * 消息事件類
 */
public class MessageEvent {
    private String message;

    public MessageEvent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

在需要訂閱事件的地方,註冊事件:

// 註冊事件
EventBus.getDefault().register(this);

發送事件:

// 發送事件
EventBus.getDefault().post(new MessageEvent("發送事件"));

處理事件:

    /**
     * 處理事件
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMoonEvent(MessageEvent messageEvent){
        // messageEvent.getMessage()就是接收的事件消息
    }

取消事件訂閱:

// 取消訂閱
EventBus.getDefault().unregister(this);

順序就是先訂閱,再發送,然後才能接收。但是也有特例,這就是黏性事件。

1.1 黏性事件

EventBus還支持黏性事件,就是在發送事件之後,再訂閱,也能接收到該事件。粘性事件會保存在內存中,每次進入都會去內存中查找獲取最新的粘性事件,除非你手動解除註冊。
訂閱者處理黏性事件:

    /**
     * 處理黏性事件
     */
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void onMoonEvent(MessageEvent messageEvent){
        // messageEvent.getMessage()就是接收的事件消息
    }

發送黏性事件:

// 發送黏性事件
EventBus.getDefault().postSticky(new MessageEvent("發送黏性事件"));

二、源碼分析

2.1 訂閱者註冊

2.1.1 EventBus.getDefault()

在使用EventBus時,要通過EventBus.getDefault()獲取EventBus實例。這個getDefault()方法用到了DCL模式

	// EventBus構造方法
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

這個單例模式中的DCL很重要,尤其是 synchronizedvolatile 這兩個關鍵字的作用。

這裏我們看到通過 new EventBus() 來創建實例,看一下這個EventBus() 都做了什麼:

    public EventBus() {
    	// DEFAULT_BUILDER就是默認的EventBusBuilder,用來構造EventBus
        this(DEFAULT_BUILDER);
    }

這個DEFAULT_BUILDER就是默認的EventBusBuilder,用來構造EventBus:

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

this調用了EventBus的有參構造:

    EventBus(EventBusBuilder builder) {
    	......
        // 1 用來存儲事件對應的 訂閱者和訂閱者方法集合映射的封裝類 
        subscriptionsByEventType = new HashMap<>();
        // 2 用來存儲註冊的訂閱者
        typesBySubscriber = new HashMap<>();
        // 3 用來存儲黏性事件
        stickyEvents = new ConcurrentHashMap<>();
        // 4 Android主線程處理事件
        mainThreadSupport = builder.getMainThreadSupport();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        // Background事件發送者
        backgroundPoster = new BackgroundPoster(this);
        // 異步事件發送者
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        // 5 @Subscribe註解方法找尋器
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
                
        ... 從builder取中一些列訂閱相關信息進行賦值
        
        // 6 執行服務線程池
        executorService = builder.executorService;
    }

關於這個有參構造:
① 首先創建了一個subscriptionsByEventType對象(K爲Event類型,V爲Subscription鏈表)。Subscription是一個訂閱信息對象,它保存了**類型爲 Object 的 subscriber(註冊的對象,通常爲Activity對象)**和類型爲SubscriberMethod 的 subscriberMethod(被@Subscribe標註的訂閱方法)
② 創建類型爲 Map 的typesBySubscriber對象,K表示subscriber對象,V表示subscriber對象中所有的 Event 類型鏈表。作用就是判斷某個對象是否註冊過
③ 新建了一個類型爲ConcurrentHashMap的stickyEvents對象,專用於黏性事件處理的一個字段。K表示事件的Class對象,V表示當前的事件

④ 新建了3種類型的事件發送器:

  • mainThreadPoster :UI線程事件發送器,通過mainThreadPoster.enqueue(subscription, event)方法可以將訂閱信息和對應的事件進行 “入隊” 操作。通過 handler 去發送消息,在 handleMessage 中執行。
  • backgroundPoster:後臺事件發送器,通過enqueue() 將方法加入到後臺的一個隊列中,最後交給 線程池 執行。在Executor#execute()方法 上添加了 synchronized 並設立了控制標記 flag,保證任一時間有且僅有一個任務被線程池執行。
  • asyncPoster:實現邏輯和backgroundPoster雷同,但asyncPoster則是異步運行的,可以同時接收多個任務。

⑤ 新建一個subscriberMethodFinder對象,這是從EventBus中抽離出的訂閱方法查詢的一個對象。
⑥ 從builder中取出一個默認的線程池對象,由Executors的newCachedThreadPool()方法創建,它是一個無數量上限的線程池(有就用,沒有就創建)。

很明顯EventBusBuilderEventBus的建造器,EventBus可以通過這個建造器,添加自定義的參數和安裝一個自定義的默認EventBus實例。這裏採用建造者模式,通過EventBusBuilder來對EventBus進行配置。這樣的設計,使得參數的配置更加靈活。

2.1.2 .register(this)

獲取到EventBus後,就將訂閱者註冊到EventBus中:

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();

		// 1.藉助訂閱方法查找器,通過註解查找訂閱者的所有訂閱方法列表
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
        	
        	// 2.遍歷訂閱方法,訂閱註冊
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

接下來查看SubscriberMethodFinder#findSubscriberMethods()方法是如何來查找訂閱者的訂閱方法的:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {

    // 1.如果緩存中有subscriberClass對象對應 的訂閱方法列表,則直接返回
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    // 2.緩存中查不到,就判斷ignoreGeneratedIndex
    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;
    }
}

以上代碼中:
① 如果緩存中有subscriberClass對象對應 的訂閱方法列表,則直接返回
② ignoreGeneratedIndex字段很重要, 它用來判斷是否使用生成的 APT 代碼去優化尋找接收事件的過程。如果開啓,那麼將會通過 subscriberInfoIndexes 來快速得到接收事件方法的相關信息。如果我們沒有在項目中接入 EventBus 的 APT,那麼可以將 ignoreGeneratedIndex 字段設爲 false 以提高性能。ignoreGeneratedIndex 默認爲false,所以會執行findUsingInfo()方法,後面生成 subscriberMethods 成功的話會加入到緩存中,失敗的話會 拋出異常。這樣是爲了避免下次重新查找!

下面看一下執行的findUsingInfo()方法:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    // 註釋1 創建一個新的 FindState 類
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    
    while (findState.clazz != null) {
   		 // 註釋2 獲取訂閱者信息
        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 {
             // 註釋3 將訂閱方法保存到findState中
             findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    // 註釋4
    return getMethodsAndRelease(findState);
}

註釋1,通過prepareFindState方法創建了一個新的FindState 類:

private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
    // 1.從 FIND_STATE_POOL 即 FindState 池中取出可用的 FindState(這裏的POOL_SIZE爲4)
    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;
            }
        }
    }
    // 2.如果沒有,就新建 一個新的 FindState 對象
    return new FindState();
}

這個方法中一共就做了兩件事:

  • ① 從FIND_STATE_POOL 即 FindState 池中取出可用的 FindState(這裏的POOL_SIZE爲4)
  • ② 如果沒有,就創建一個新的 FindState對象

這個FindState 是SubscriberMethodFinder 的內部類,主要做一些初始化、回收對象的工作:

   // FindState中間器,用於查找保存狀態
    static class FindState {
    
        ......
        
        // 初始化傳入訂閱類
        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

        // 回收釋放,已備複用
        void recycle() {...}

        // 用來判斷FindState的anyMethodByEventType map是否已經添加過以當前eventType爲key的鍵值對,沒添加過則返回true
        boolean checkAdd(Method method, Class<?> eventType) {...}

        // 移動到父類Class
        void moveToSuperclass() {...}

SubscriberMethodFinder的註釋2的getSubscriberInfo()方法獲取訂閱者信息:

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;
        }
    }
    if (subscriberInfoIndexes != null) {
        for (SubscriberInfoIndex index: subscriberInfoIndexes) {
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

由於在上一步初始化的時候,findState的subscriberInfo和subscriberInfoIndexes 這兩個字段都爲null,於是直接在最後return null。

註釋3,findUsingReflectionInSingleClass()方法:

private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // 反射得到所有訂閱者的訂閱方法
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    }
    for (Method method: methods) {
        int modifiers = method.getModifiers();
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            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();
                        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");
        }
    }
}

這個方法做了一堆的事情:

  • ① 利用反射來獲取訂閱者類中的所有聲明方法,在這些方法裏面尋找以 @Subscribe作爲註解的方法進行處理
  • ② 在經過經過一輪檢查,看看 findState.subscriberMethods是否存在,如果沒有,將方法名,threadMode,優先級,是否爲 sticky 方法等信息封裝到 SubscriberMethod 對象中,最後添加到 subscriberMethods 列表中

註釋4,getMethodsAndRelease()方法:

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
    // 1.從findState中取出了保存的subscriberMethods
    List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
    // 2.將findState裏的保存的所有對象進行回收
    findState.recycle();
    // 3.把findState存儲在 FindState 池中方便下一次使用,以提高性能
    synchronized(FIND_STATE_POOL) {
        for (int i = 0; i < POOL_SIZE; i++) {
            if (FIND_STATE_POOL[i] == null) {
                FIND_STATE_POOL[i] = findState;
                break;
            }
        }
    }
    // 4.返回subscriberMethods
    return subscriberMethods;
}

以上方法做了4件事:
① 從findState中取出了保存的subscriberMethods
② 將findState裏的保存的所有對象進行回收
③ 把findState存儲在 FindState 池中方便下一次使用,以提高性能
④ 返回subscriberMethods

最後,在EventBus的 register() 方法的最後會調用 subscribe 方法:

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


// subscribe方法
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    // 1.根據訂閱者Subscriber和訂閱方法SubscriberMethod,創建訂閱對象Subscription
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

    // 2.根據事件類型EventType獲取訂閱對象集合Subscriptions,並將其保存到Map中
    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();

    // 3.按照訂閱方法的優先級插入到訂閱對象集合中,完成訂閱方法的註冊
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    // 4.獲取事件類型集合,將eventType添加其中,並將其按照subscriber存儲到Map中
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
    // 5.判斷是否是黏性事件
    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);
        }
    }
}

這個方法做了四件事:

  • ① 根據訂閱者Subscriber和訂閱方法SubscriberMethod,創建訂閱對象Subscription
  • ② 根據事件類型eventType獲取訂閱對象集合subscriptions(null則重新創建),並將subscriptions按照eventType保存到Map中
  • ③ 按照訂閱方法的優先級,插入到訂閱對象集合中,完成訂閱方法的註冊
  • ④ 通過訂閱者subscriber獲取事件類型集合subscribedEvents(null則創建),並將eventType添加到subscribedEvents中,根據subscriber將subscribedEvents保存到Map中。
  • ⑤ 判斷是否是黏性事件。如果是,會從stickyEvent事件保存隊列中取出該事件類型的事件,調用 checkPostStickyEventToSubscription() 方法來發送給當前訂閱者

2.2 post()

	// 將給定事件發佈到事件總線
    public void post(Object event) {
	
		// 1.保存着事件隊列和線程狀態信息
        PostingThreadState postingState = currentPostingThreadState.get();
        // 獲取事件隊列,將當前事件插入事件隊列中
        List<Object> eventQueue = postingState.eventQueue;
        // 將傳入的event保存到eventQueue中
        eventQueue.add(event);

		// 2.將隊列中的時間依次交給postSingleEvent方法,並移除該事件
        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;
            }
        }
    }

這個currentPostingThreadState 是 ThreadLocal 類型的對象,裏面存儲了 PostingThreadState(PostingThreadState 中包含了一個 時間隊列eventQueue 和其他一些線程信息)。關於這個PostingThreadState:


    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
    
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<>();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;
    }

總的來說,就是先從PostingThreadState 對象中取出事件隊列eventQueue,將當前事件插入到eventQueue中,再將eventQueue中的事件依次交給postSingleEvent方法處理,最後移除該事件。

接着會調用postSingleEvent() 方法:

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {

	// 取出 Event 的 class 類型
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    // 1. 是否向上查找事件的父類。默認true
    if (eventInheritance) {
        // 2.取出 Event 及其父類和接口的 class 列表
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            subscriptionFound |=
            // 3
            postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    if (!subscriptionFound) {
        ...
    }
}

這個postSingleEvent() 方法:

  • ① 判斷eventInheritance 標誌位,即是否向上查找事件的父類。默認爲true,false的話可以提升一些性能
  • ② 調用lookupAllEventTypes() 方法,取出 Event 及其父類和接口的 class 列表。由於重複取會影響性能,所以做了一個 eventTypesCache 的緩存,避免了重複調用 getSuperclass() 方法
  • ③ 調用postSingleEventForEventType()方法

關於這個postSingleEventForEventType()方法:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class <?> eventClass) {
    CopyOnWriteArrayList <Subscription> subscriptions;
    // 同步取出訂閱對象集合
    synchronized(this) {
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
    // 遍歷,將event對應的訂閱對象subscription傳遞給postingState
        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;
}

這個postSingleEventForEventType()方法中,根據 Event 類型從 subscriptionsByEventType 中取出對應的 subscriptions對象,最後調用了 postToSubscription() 方法:

// 發佈到訂閱者,根據threadMode進行線程切換
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 {
            	// 如果是在子線程發送事件,則將事件入隊列,通過Handler切換到主線程執行處理事件
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case MAIN_ORDERED://無論在哪個線程發送事件,都先將事件入隊列,然後通過 Handler 切換到主線程,依次處理事件。mainThreadPoster不會爲null
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        case BACKGROUND: //若UI線程發佈,就在新線程處理;若在子線程發佈,就在當前線程處理
            if (isMainThread) {
                backgroundPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC: //無論在哪個線程發佈,都會在新線程中處理
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknow thread mode: " + subscription.subscriberMethod.threadMode);
    }
}

通過線程模型threadMode 來判斷在哪個線程中去執行方法,關於這幾種線程模型,上面已經介紹過了。

2.3 unregister()

public synchronized void unregister(Object subscriber) {

	// 獲取訂閱者訂閱的所有事件
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
    	// 遍歷訂閱類型集合,釋放之前緩存的當前類中的Subscription
        for (Class<?> eventType : subscribedTypes) {
            // 重點1
            unsubscribeByEventType(subscriber, eventType);
        }
        // 重點2 刪除以subscriber爲key的鍵值對,更新typesBySubscriber
        typesBySubscriber.remove(subscriber);
    }
}

首先會獲取訂閱者訂閱的所有事件,遍歷它,並調用unsubscribeByEventType方法,釋放之前緩存的當前類中所有的訂閱信息Subscription

   // 僅更新subscriptionsByEventType,而不更新typesBySubscriber
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        // 得到當前參數類型對應的Subscription集合
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            // 遍歷這個Subscription集合
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                 // 如果當前subscription對象對應的註冊類對象 和 要取消註冊的註冊類對象相同,則刪除當前subscription對象
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

隨後調用remove方法,移除了註冊對象和其對應的所有 Event 事件鏈表

2.4 postSticky()

public void postSticky(Object event) {
    synchronized (stickyEvents) {
        // 1.將黏性事件放到stickyEvents中
        stickyEvents.put(event.getClass(), event);
    }
    // 2.調用post方法發送
    post(event);
}

在register的最後提到了黏性:

if (subscriberMethod.sticky) {
    Object stickyEvent = stickyEvents.get(eventType);
    if (stickyEvent != null) {
        postToSubscription(newSubscription, stickyEvent, isMainThread());
    }
}

判斷當前事件是否是 sticky 事件,如果 是,則從 stickyEvents 中拿出該事件並執行 postToSubscription() 方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章