EventBus源碼解析(一)———EventBus的註冊通過反射方式查找訂閱者

文章列表

EventBus源碼解析(一)
EventBus源碼解析(二)
EventBus源碼解析(三)

前言

在公司項目中經常用到EventBus庫,它使消息的傳遞變得相當簡單,但是隻會用是不行的,今天就來分析一下EventBus的源碼。看看它到底是什麼原理。

基本用法

由淺入深,還是先來看一下EventBus是怎麼用的,已經把EventBus的使用方式熟讀於心的小夥伴,可以忽略此部分內容。
這裏只寫一個最簡單的用法,兩個Activity之間的傳值
第一個Activity:

public class ActivityA extends AppCompatActivity {
    TextView textView;
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
        textView = findViewById(R.id.text);
       
    }
	 @Override
	 public void onStart() {
	     super.onStart();
	     //步驟1、獲取實例並註冊
         EventBus.getDefault().register(this);;
	 }
	
	 @Override
	 public void onStop() {
	     super.onStop();
	     EventBus.getDefault().unregister(this);
	 }

	//步驟2、編寫回調
    @Subscribe
    public void onEvent(MessageEvent event){
        if ("FromActivityB".equals(event.key) && !TextUtils.isEmpty(event.text)){
            textView.setText(event.text);
        }
    }

    public void onClick(View view){
        Intent intent = new Intent(this,ActivityB.class);
        startActivity(intent);
    }
}

第二個Activity:

public class ActivityB extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);
    }

    public void onClick(View view){
    	//步驟3獲取實例併發送消息
        EventBus.getDefault().post(new MessageEvent("FromActivityB","來自ActivityB的數據"));
    }
}

很簡單、提煉出步驟就是:
在接收消息的組件中:
1、獲取EventBus實例並註冊,即EventBus.getDefault().register(this);
2、實現消息回調方法,即自定義只有一個參數的方法並添加@Subscribe註解,及相關參數
3、取消註冊EventBus.getDefault().unregister(this);
在發送消息的組件中:
1、獲取實例併發送消息,即EventBus.getDefault().post(new MessageEvent("FromActivityB","來自ActivityB的數據"));

分析源碼之前,先看一下Subscribe註解帶什麼參數:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}

有三個參數:threadModestickypriority
第一個參數ThreadMode,可取的值有POSTINGMAINMAIN_ORDEREDBACKGROUNDASYNC,簡單解釋一下這幾個值的意義:
POSTINGThreadMode的默認取值,訂閱方法會在跟事件發送在同一個線程調用;
MAIN:訂閱方法會在Android UI線程調用;
MAIN_ORDERED:訂閱方法會在Android UI線程中按順序調用;與MAIN不同的是這個事件是非阻塞式的傳遞;
BACKGROUND:在Android中,訂閱方法會在後臺線程調用,如果發送事件的線程不是主線程,則訂閱方法的調用線程就會跟發送事件的線程是同一個;否則的話,就會在開啓一個後臺線程,按順序的處理事件,訂閱者需要很快的處理這個事件,防止阻塞後臺線程;
ASYNC:訂閱方法總是會新開啓一個線程處理事件,它不會等訂閱方法執行完才發下一個消息,EventBus是使用線程池實現的這個模式;
第二個參數sticky用來表示是否處理黏性事件、黏性事件是通過EventBus的postSticky(Object object)方法發送的,默認值是false;
第三個參數priority表明訂閱者處理事件的優先級,同樣的ThreadMode的情況下,優先級越高,會先收到發送的事件,默認的優先級是0;

分析源碼

使用步驟有了,那就按着使用步驟一步一步的分析源碼。
第一步:獲取實例,EventBus.getDefault();
看一下getDefault()方法是什麼

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<>();
    //...省略代碼...
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
}

這就是通過單例模式、來獲取一個EventBus的實例,而EventBus的屬性是通過一個Builder提供的默認值,這些屬性先按着默認值來繼續往下走。
第二步:註冊觀察者。eventBus.register(this);
看下register(this)方法的代碼

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    //根據傳進來的類的類型,查找訂閱的方法
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    //同步處理,循環去訂閱消息
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

SubscriberMethodFinder類用於處理查找訂閱方法並且緩存訂閱方法,在這裏可以理解爲一個“查找助手”。在上面的方法中可以看到這裏又分了兩步:1、查找;2、訂閱;
我們分開來看
a)、查找:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
	//在緩存中查找方法, METHOD_CACHE是一個HashMap,key爲訂閱者類,value爲訂閱者類的方法集合
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }
	//是否忽略註解生成的SubscriberInfoIndex索引去查找=======標記一
	//上面我們的用法中,沒有設置EventBusBuilder的ignoreGeneratedIndex屬性,所以取默認值false,會走進else分支中
    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中,以便下次查找的時候,可以直接從緩存中取
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}

上面的代碼中註釋寫的很清楚,這個方法會調用else分支中的findUsingInfo(subscriberClass);方法,接着看:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
	//獲取一個FindState實例
    FindState findState = prepareFindState();
    //初始化參數
    findState.initForSubscriber(subscriberClass);
	//循環處理、循環的是向當前類的父類中繼續查找
    while (findState.clazz != null) {
    	//查找訂閱者信息---註釋1
        findState.subscriberInfo = getSubscriberInfo(findState);
        if (findState.subscriberInfo != null) {
        	//獲取訂閱者中的訂閱方法的信息
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
            	//針對每個訂閱方法進行"一些"檢查(至於檢查什麼,我們後面會說)並存儲在findState中的anyMethodByEventType變量中
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                	//如果返回true,就將訂閱方法存儲在findState的subscriberMethods變量中
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {//如果findState的subscriberInfo爲null、就通過反射的方式去查找
            findUsingReflectionInSingleClass(findState);
        }
        //處理完、需要向父類中移動,繼續查找父類
        findState.moveToSuperclass();
    }
    //釋放資源並返回訂閱方法集合
    return getMethodsAndRelease(findState);
}

SubscriberMethodFinder內部有一個靜態內部類FindState,此類保存了一些查找過程中用到的臨時變量、並且檢查訂閱方法是否已經存在,並保存。
先一步一步看findUsingInfo
第一步,準備FindState,先看調用的prepareFindState方法:

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

FIND_STATE_POOL這是什麼東西?

private static final int POOL_SIZE = 4;
//FindState對象池
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];

原來是從對象池中取的對象,節省資源開銷;
第二步:初始化:調用FindState類的findState.initForSubscriber(subscriberClass);方法

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

把訂閱的類(即我們的ActivityA.class)賦值給findState對象的subscriberClassclazz變量,並把subscriberInfo置爲null,這裏稍微注意一下,後面要用;
第三步:進入循環,調用getSubscriberInfo(findState);

private SubscriberInfo getSubscriberInfo(FindState findState) {
	//上面subscriberInfo在findState初始化的時候,被置爲null,所以if中的語句不會執行,先略過、
    if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
        SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
        if (findState.clazz == superclassInfo.getSubscriberClass()) {
            return superclassInfo;
        }
    }
    //subscriberInfoIndexes是通過SubscriberMethodFinder的構造方法賦值,默認的情況下這個值爲null,所以if語句不執行、先略過
    if (subscriberInfoIndexes != null) {
        for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

看註釋,也就是說這個方法返回null;findUsingInfo(Class<?> subscriberClass)方法的註釋1處,得到的返回值爲null,所以會走進else邏輯,調用方法findUsingReflectionInSingleClass(findState);
第四步:通過反射查找,調用findUsingReflectionInSingleClass方法

private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // 獲取當前類中聲明的方法,不包括從父類的繼承的
        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並且沒有abstract、static、bridge、synthetic這些限定符
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
        	//獲取所有參數類型
            Class<?>[] parameterTypes = method.getParameterTypes();
            //過濾掉參數不爲1個的方法
            if (parameterTypes.length == 1) {
            	//獲取@Subscribe註解
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
               //用@Subscribe註解的才能滿足條件
                if (subscribeAnnotation != null) {
                	//獲取參數類型
                    Class<?> eventType = parameterTypes[0];
                    //根據參數類型存儲method到findState的anyMethodByEventType變量中
                    if (findState.checkAdd(method, eventType)) {
                    	//若存儲成功,就繼續獲取註解的ThreadMode參數
                        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)) {
                //省略異常...
        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
           //省略異常
        }
    }
}

這裏看到有一個if(findState.checkAdd(method, eventType))這個判斷,之前在findUsingInfo方法中也有這邏輯,但是沒有走進去,但是在findUsingReflectionInSingleClass這個方法中走進了這個邏輯,我們跟進去看看做了哪些工作

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

由於checkAddWithMethodSignature方法和checkAdd方法聯繫比較緊密、所以把checkAddWithMethodSignature方法貼出來

private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());
			//用method名+“>”+eventType名做Key,Value爲method,把映射關係存進subscriberClassByMethodKey中
            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;
            }
        }

第一個方法有註釋,翻譯一下就是:這是一個二級檢查,第一級檢查是快速檢查,根據eventType做的檢查,如果有第二級檢查的話、第二級檢查是根據簽名來做的校驗,後面還有一句:意思是一般情況下,一個訂閱者不會有好幾個方法同時來監聽事件。來看一下是怎麼做的檢查
FindeState中維護着一個Map<Class, Object>類型的變量anyMethodByEventType,用來存放eventTypemethod的映射關係
此方法中,先把傳進來的eventTypemethod存進去,如果返回值爲null證明之前anyMethodByEventType中沒有K爲eventType的值,否則的話說明已經存在一個監聽此類事件的方法(通常情況不會有兩個),會把任何一個非Method對象(這裏是FindState對象本身)存進去“消費”掉這個已經存在的方法。並把對同一個事件監聽的方法存進subscriberClassByMethodKey變量中,其中以method的name+“>”+event的名字作爲key,method作爲value。

舉個例子:如果一個方法中有兩個(兩個以上同理)方法同時對同一個事件監聽,遍歷這些方法分別調用checkAdd方法,第一個方法映射關係會存進anyMethodByEventType,當遍歷到第二個方法的時候,會導致existing不爲null,進入else分支,並進行判斷if (!checkAddWithMethodSignature((Method) existing, eventType)),這個方法中會把置換出來的方法,即第一次存入anyMethodByEventType變量中的方法,將它以簽名作爲key的形式存入subscriberClassByMethodKey,而後調用anyMethodByEventType.put(eventType, this);,將當前對象(即FindState對象)入anyMethodByEventType中,key爲eventType;,然後繼續調用checkAddWithMethodSignature,將第二個對當前事件監聽的方法,也以簽名爲key的形式存入subscriberClassByMethodKey對象中,如果此時有第三個對同一事件監聽的方法進入checkAdd方法的話,會直接走return checkAddWithMethodSignature(method, eventType);以簽名爲key的形式存進subscriberClassByMethodKey中,如果第四個呢?第四個話會和第二個的執行流程一樣。讀者可以自己再看一下這個邏輯。

所有的方法都執行完後,回到findUsingReflectionInSingleClass中,findState.subscriberMethods變量裏就會把剛纔遍歷的所有的訂閱方法加進去。至此返回到上一級方法。

到這裏才只是走完findUsingInfo方法中的else部分的邏輯,繼續往下走
調用到了findState.moveToSuperclass();

void moveToSuperclass() {
	//skipSuperClasses默認false
    if (skipSuperClasses) {
        clazz = null;
    } else {
    	//重置clazz爲其父類
        clazz = clazz.getSuperclass();
        String clazzName = clazz.getName();
        /** 跳過系統提供的類 */
        if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
            clazz = null;
        }
    }
}

調用完moveToSuperclass方法後,這個clazz屬性就成爲其父類,然後繼續尋找父類中的訂閱的方法,注意:父類中不用再去單獨調用Event.getDefault.register(this)
最後還有一個釋放資源的方法:

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        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;
    }

這個就是把findState對象中的subscriberMethods取到返回,並把findState對象放回緩存池。
以上是對查找的分析,接下來開始分析訂閱
b)、訂閱

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(subscriber, subscriberMethod);

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
	//獲取訂閱方法的監聽事件的類型
    Class<?> eventType = subscriberMethod.eventType;
    //將訂閱方法和訂閱者封裝到一個Subscription對象中
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //監聽相同類型的事件的由訂閱方法和訂閱者組成的對象存到一個list中,這個list是存儲在,以事件類型爲key,list爲value的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);
        }
    }
	//遍歷list,並根據當前訂閱方法的優先級存儲到list的合適的位置
    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;
        }
    }

	//typesBySubscriber用來存儲一個訂閱者中監聽的所有類型的事件的list
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    //將事件類型存入事件類型list中
    subscribedEvents.add(eventType);
	//到此非黏性事件的註冊方法就執行完了
	//如果事件訂閱方法支持監聽黏性事件需要做如下處理
    if (subscriberMethod.sticky) {
        if (eventInheritance) {//事件是否需要繼承,在Builder中修改這個屬性,默認是true
            // 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>).
            //翻譯一下(英語好的自行略過,翻譯有誤請指出):意思就是需要考慮,現有的 所有事件類型的子類 的事件。(注意斷句)
            //注意:遍歷所有的黏性事件效率可能很低
            //所以需要有一個查找效率很高數據結構
            //(舉例:額外用一個map來存儲子類)
            //翻譯結束------我是分隔符-----
            // stickyEvents這是個什麼東西?恩看名字應該是黏性事件集合?什麼時候來的?先存疑一下,看看後面會不會出現這個傢伙,暫且按着字面意思理解
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            //遍歷黏性事件
            for (Map.Entry<Class<?>, Object> entry : entries) {
                Class<?> candidateEventType = entry.getKey();
                //做一下篩選,判斷當前事件類型的類是不是與集合中某一個事件類型的類是同一個或是是其父類或接口(有點繞好好捋一捋),其實就是判斷有沒有繼承關係,滿組條件的話、執行checkPostStickyEventToSubscription方法
                if (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {//如果忽略繼承關係的話、就只針對當前時間執行checkPostStickyEventToSubscription方法
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

代碼中的註釋寫的比較清楚,在簡單捋一遍:

  • 參數subscriber就是我們的ActivityA
  • 參數SubscriberMethod就是對訂閱方法的一些屬性的封裝,包括ThreadModepriority等屬性、一個SubscriberMethod標識一個訂閱方法;
  • 局部變量subscriptions的類型是CopyOnWriteArrayList<Subscription>,是用來存放監聽同一個事件類型的Subscription對象的;
  • 全局變量subscriptionsByEventType的類型是Map<Class<?>, CopyOnWriteArrayList<Subscription>>,其中key是eventType,value就是上面的變量subscriptions;
  • 全局變量typesBySubscriberMap<Object, List<Class<?>>>類型的,其中key是訂閱者對象,在這裏即ActivityA,value是eventType類型的list;

subscribe方法的流程
方法先把subscriberSubscriberMethod封裝到一個Subscription類型的對象newSubscription中,然後從subscriptionsByEventType中獲取Subscription的list,然後做一些初始化或者判斷是否已經包含newSubscription
然後循環遍歷subscriptions,根據當前方法的優先級判斷將newSubscription插入到list的合適位置或者末尾。
然後根據subscriber取出eventType的list,如果爲空初始化,並插入到typesBySubscriber,並將當前方法監聽的事件add到list中

注意:到這裏所有的訂閱方法的信息就會保存到subscriptionsByEventType變量中,如果是非黏性方法,則註冊的邏輯到此就走完了。下一篇文章,我們開始講解事件的發送EventBus的post等系列方法。

如果監聽方法支持黏性事件,還要多走一步邏輯
a)如果需要繼承,就遍歷黏性事件集合,如果是當前事件的父類就調用checkPostStickyEventToSubscription(newSubscription, stickyEvent);;
b)如果不需要繼承,就只針對當前事件調用checkPostStickyEventToSubscription(newSubscription, stickyEvent);;
結束。

看下方法checkPostStickyEventToSubscription的源碼會發現,判斷參數stickyEvent不爲空的情況下直接調用postToSubscription,貼出postToSubscription方法

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

在這個方法中我們看到了熟悉的身影,判斷監聽方法的ThreadMode參數,對應我們監聽方法的註解中的ThreadMode的設置的值,因爲我們在文章開頭的例子中的ThreadMode取的是默認值POSTING,所以我們只看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);
        }
    }

就是利用反射機制調用了invoke方法。也就是說、如果監聽事件支持黏性方法,則在監聽者註冊的以後,會觸發監聽方法回調,去處理髮送過來的黏性事件。
事件的發送,我們留到EventBus源碼解析(二)————EventBus事件發送

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