EventBus用法及源碼解析

EventBus用法及源碼解析
目錄介紹
1.EventBus簡(jiǎn)介
1.1 EventBus的三要素
1.2 EventBus的四種ThreadMode(線程模型)
1.3 EventBus怎么調(diào)用
2.EventBus使用
2.1 最簡(jiǎn)單的使用
3.EventBus注冊(cè)源碼解析
3.1 EventBus.getDefault()獲取對(duì)象
3.2 register(this)注冊(cè)源碼解析
3.2.1 首先看register(this)源碼
3.2.2 接下來(lái)看findSubscriberMethods(subscriberClass)里面的源碼
3.2.3 接下來(lái)看findUsingInfo(subscriberClass)源碼
3.3 查找完所有的訂閱方法后便開(kāi)始對(duì)所有的訂閱方法進(jìn)行注冊(cè)
3.3.1 subscribe(subscriber, subscriberMethod);
3.3.2 訂閱者的注冊(cè)過(guò)程
3.3.3 流程圖
4.EventBus事件分發(fā)解析
4.1 從post方法入手
4.2 什么是PostingThreadState?
4.3 PostingThreadState怎么獲得?
4.4 來(lái)看看postSingleEvent方法里做了什么
4.5 接下來(lái)看看postSingleEventForEventType方法
4.6 接下來(lái)看看postToSubscription方法
4.7 整個(gè)流程圖
4.8 總結(jié)一下整個(gè)事件分發(fā)的過(guò)程
5.EventBus取消注冊(cè)解析
5.1 unregister(this)方法入手
5.2 再來(lái)看看unsubscribeByEventType(subscriber, eventType)
5.3 取消注冊(cè)流程圖
5.4 總結(jié)一下取消注冊(cè)的過(guò)程
6.總結(jié)一下EventBus的工作原理
6.1 訂閱邏輯
6.2 事件發(fā)送邏輯
6.3 取消邏輯
6.4 利與弊
7.其他介紹
7.1 參考文檔
7.2 其他

好消息

  • 博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開(kāi)發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長(zhǎng)期更新維護(hù)并且修正,持續(xù)完善……開(kāi)源的文件是markdown格式的!同時(shí)也開(kāi)源了生活博客,從12年起,積累共計(jì)47篇[近20萬(wàn)字],轉(zhuǎn)載請(qǐng)注明出處,謝謝!
  • 鏈接地址:https://github.com/yangchong211/YCBlogs
  • 如果覺(jué)得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬(wàn)事起于忽微,量變引起質(zhì)變!

1.EventBus簡(jiǎn)介

  • 1.1 EventBus的三要素**
    • Event:事件
      可以是任意類型的對(duì)象。
    • Subscriber:事件訂閱者
      在EventBus3.0之前,消息處理的方法只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,他們分別代表四種線程模型。
      在EventBus3.0之后,事件處理的方法可以隨便取名,但是需要添加一個(gè)注解@Subscribe,并且要指定線程模型(默認(rèn)為POSTING),四種線程模型下面會(huì)講到。
    • Publisher:事件發(fā)布者
      可以在任意線程任意位置發(fā)送事件,直接調(diào)用EventBus的post(Object)方法。可以自己實(shí)例化EventBus對(duì)象,但一般使用EventBus.getDefault()就好了,根據(jù)post函數(shù)參數(shù)的類型,會(huì)自動(dòng)調(diào)用訂閱相應(yīng)類型事件的函數(shù)。
  • 1.2 EventBus的四種ThreadMode(線程模型)**
    • POSTING(默認(rèn)):
      如果使用事件處理函數(shù)指定了線程模型為POSTING,那么該事件在哪個(gè)線程發(fā)布出來(lái)的,事件處理函數(shù)就會(huì)在這個(gè)線程中運(yùn)行,也就是說(shuō)發(fā)布事件和接收事件在同一個(gè)線程。在線程模型為POSTING的事件處理函數(shù)中盡量避免執(zhí)行耗時(shí)操作,因?yàn)樗鼤?huì)阻塞事件的傳遞,甚至有可能會(huì)引起ANR。
    • MAIN:
      事件的處理會(huì)在UI線程中執(zhí)行。事件處理時(shí)間不能太長(zhǎng),長(zhǎng)了會(huì)ANR的。
    • BACKGROUND:
      如果事件是在UI線程中發(fā)布出來(lái)的,那么該事件處理函數(shù)就會(huì)在新的線程中運(yùn)行,如果事件本來(lái)就是子線程中發(fā)布出來(lái)的,那么該事件處理函數(shù)直接在發(fā)布事件的線程中執(zhí)行。在此事件處理函數(shù)中禁止進(jìn)行UI更新操作。
    • ASYNC:
      無(wú)論事件在哪個(gè)線程發(fā)布,該事件處理函數(shù)都會(huì)在新建的子線程中執(zhí)行,同樣,此事件處理函數(shù)中禁止進(jìn)行UI更新操作。
  • 1.3 EventBus怎么調(diào)用**
    代碼如下: EventBus.getDefault().post(param);
    • 調(diào)用原理簡(jiǎn)單理解為:
    • 一句話,你也可以叫發(fā)布,只要把這個(gè)param發(fā)布出去,EventBus會(huì)在它內(nèi)部存儲(chǔ)的方法中,進(jìn)行掃描,找到參數(shù)匹配的,就使用反射進(jìn)行調(diào)用。
    • 撇開(kāi)專業(yè)術(shù)語(yǔ):其實(shí)EventBus就是在內(nèi)部存儲(chǔ)了一堆onEvent開(kāi)頭的方法,然后post的時(shí)候,根據(jù)post傳入的參數(shù),去找到匹配的方法,反射調(diào)用之。
    • 它內(nèi)部使用了Map進(jìn)行存儲(chǔ),鍵就是參數(shù)的Class類型。知道是這個(gè)類型,那么你覺(jué)得根據(jù)post傳入的參數(shù)進(jìn)行查找還是個(gè)事么?

2.EventBus使用

  • 2.1 最簡(jiǎn)單的使用
  • 2.1.1 自定義一個(gè)事件類
public class MessageEvent {

}
  • 2.1.2 在需要訂閱事件的地方注冊(cè)事件
EventBus.getDefault().register(this);
  • 2.1.3 發(fā)送事件
EventBus.getDefault().post(messageEvent);
  • 2.1.4 處理事件
    • 3.0之后, 消息處理的方法可以隨便取名
      問(wèn)題: (threadMode = ThreadMode.MAIN)是做什么用的??
      需要添加一個(gè)注解@Subscribe,并且要指定線程模型
      如果沒(méi)有添加,那就是默認(rèn)為POSTING
@Subscribe(threadMode = ThreadMode.MAIN)
public void Hhhh(MessageEvent messageEvent) {
...
}
  • 2.1.5 取消事件訂閱
EventBus.getDefault().unregister(this);

3.EventBus注冊(cè)源碼解析

  • 3.1 EventBus.getDefault()獲取對(duì)象
  • a.先看源碼:
/** 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;
}
  • b.分析
    單例模式, 使用了雙重判斷的方式,防止并發(fā)的問(wèn)題,還能極大的提高效率
  • 3.2 register(this)注冊(cè)源碼解析
  • 3.2.1.首先看register(this)源碼
public void register(Object subscriber) {
    //首先獲取訂閱者的類對(duì)象
    Class<?> subscriberClass = subscriber.getClass();
    //用 subscriberMethodFinder 提供的方法,找到在 subscriber 這個(gè)類里面訂閱的內(nèi)容。
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        //
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}
  • 3.2.2.接下來(lái)看findSubscriberMethods(subscriberClass)里面的源碼
    • 該方法的作用其實(shí)就是從訂閱類中獲取所有的訂閱方法信息
    • findSubscriberMethods找出一個(gè)SubscriberMethod的集合,也就是傳進(jìn)來(lái)的訂閱者所有的訂閱的方法,接下來(lái)遍歷訂閱者的訂閱方法來(lái)完成訂閱者的訂閱操作。對(duì)于SubscriberMethod(訂閱方法)類中,主要就是用保存訂閱方法的Method對(duì)象、線程模式、事件類型、優(yōu)先級(jí)、是否是粘性事件等屬性。
    • 源碼分析:首先從緩存中查找,如果找到了就立馬返回。如果緩存中沒(méi)有的話,則根據(jù) ignoreGeneratedIndex 選擇如何查找訂閱方法,ignoreGeneratedIndex屬性表示是否忽略注解器生成的MyEventBusIndex。最后,找到訂閱方法后,放入緩存,以免下次繼續(xù)查找。ignoreGeneratedIndex 默認(rèn)就是false,可以通過(guò)EventBusBuilder來(lái)設(shè)置它的值。我們?cè)陧?xiàng)目中經(jīng)常通過(guò)EventBus單例模式來(lái)獲取默認(rèn)的EventBus對(duì)象,也就是ignoreGeneratedIndex為false的情況,這種情況調(diào)用了findUsingInfo方法
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    //首先從緩存中讀取
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }
    //是否忽略注解器生成的MyEventBusIndex類
    if (ignoreGeneratedIndex) {
        //利用反射來(lái)獲取訂閱類中的訂閱方法信息
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        //從注解器生成的MyEventBusIndex類中獲得訂閱類的訂閱方法信息
        subscriberMethods = findUsingInfo(subscriberClass);
    }

    //在獲得subscriberMethods以后,如果訂閱者中不存在@Subscribe注解并且為public的訂閱方法,則會(huì)拋出異常。
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        //保存進(jìn)緩存
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}
//METHOD_CACHE,是一個(gè)map集合,鍵是class類型
Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
  • 3.2.3 接下來(lái)看findUsingInfo(subscriberClass)源碼
    • 通過(guò)getSubscriberInfo方法來(lái)獲取訂閱者信息。在我們開(kāi)始查找訂閱方法的時(shí)候并沒(méi)有忽略注解器為我們生成的索引MyEventBusIndex,如果我們通過(guò)EventBusBuilder配置了MyEventBusIndex,便會(huì)獲取到subscriberInfo,調(diào)用subscriberInfo的getSubscriberMethods方法便可以得到訂閱方法相關(guān)的信息,這個(gè)時(shí)候就不在需要通過(guò)注解進(jìn)行獲取訂閱方法。如果沒(méi)有配置MyEventBusIndex,便會(huì)執(zhí)行findUsingReflectionInSingleClass方法,將訂閱方法保存到findState中。最后再通過(guò)getMethodsAndRelease方法對(duì)findState做回收處理并反回訂閱方法的List集合。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        //獲取訂閱者信息,沒(méi)有配置MyEventBusIndex返回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 {
            //通過(guò)反射來(lái)查找訂閱方法
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}
  • 3.3 查找完所有的訂閱方法后便開(kāi)始對(duì)所有的訂閱方法進(jìn)行注冊(cè)
  • 3.3.1 回到
    register(this)這個(gè)方法


    Image.png
  • 3.3.2 訂閱者的注冊(cè)過(guò)程
    • 訂閱的代碼主要就做了兩件事,第一件事是將我們的訂閱方法和訂閱者封裝到subscriptionsByEventType和typesBySubscriber中,subscriptionsByEventType是我們投遞訂閱事件的時(shí)候,就是根據(jù)我們的EventType找到我們的訂閱事件,從而去分發(fā)事件,處理事件的;typesBySubscriber在調(diào)用unregister(this)的時(shí)候,根據(jù)訂閱者找到EventType,又根據(jù)EventType找到訂閱事件,從而對(duì)訂閱者進(jìn)行解綁。第二件事,如果是粘性事件的話,就立馬投遞、執(zhí)行。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    //獲取訂閱方法的參數(shù)類型 
    Class<?> eventType = subscriberMethod.eventType;
    //根據(jù)訂閱者和訂閱方法構(gòu)造一個(gè)訂閱事件
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //獲取當(dāng)前訂閱事件中Subscription的List集合
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    //該事件對(duì)應(yīng)的Subscription的List集合不存在,則重新創(chuàng)建并保存在subscriptionsByEventType中
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
    //訂閱者已經(jīng)注冊(cè)則拋出EventBusException
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }

    //遍歷訂閱事件,找到比subscriptions中訂閱事件小的位置,然后插進(jìn)去
    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;
        }
    }

     //通過(guò)訂閱者獲取該訂閱者所訂閱事件的集合
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }

      //將當(dāng)前的訂閱事件添加到subscribedEvents中
    subscribedEvents.add(eventType);
    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);
        }
    }
}
  • 3.3.3 流程圖


    Image.png

4.EventBus事件分發(fā)解析

  • 4.1 從post方法入手
    首先從PostingThreadState對(duì)象中取出事件隊(duì)列,然后再將當(dāng)前的事件插入到事件隊(duì)列當(dāng)中。最后將隊(duì)列中的事件依次交由postSingleEvent方法進(jìn)行處理,并移除該事件。
/** Posts the given event to the event bus. */
public void post(Object event) {
    //獲取當(dāng)前線程的postingState
    PostingThreadState postingState = currentPostingThreadState.get();
    //取得當(dāng)前線程的事件隊(duì)列
    List<Object> eventQueue = postingState.eventQueue;
    //將該事件添加到當(dāng)前的事件隊(duì)列中等待分發(fā)
    eventQueue.add(event);
    if (!postingState.isPosting) {
        //判斷是否是在主線程post
        postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
            while (!eventQueue.isEmpty()) {
                //分發(fā)事件
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}
  • 4.2 什么是PostingThreadState?
    PostingThreadState中包含了當(dāng)前線程的事件隊(duì)列,就是當(dāng)前線程所有分發(fā)的事件都保存在eventQueue事件隊(duì)列中以及訂閱者訂閱事件等信息,有了這些信息我們就可以從事件隊(duì)列中取出事件分發(fā)給對(duì)應(yīng)的訂閱者
final static class PostingThreadState {
    final List<Object> eventQueue = new ArrayList<Object>();//當(dāng)前線程的事件隊(duì)列
    boolean isPosting;//是否有事件正在分發(fā)
    boolean isMainThread;//post的線程是否是主線程
    Subscription subscription;//訂閱者
    Object event;//訂閱事件
    boolean canceled;//是否取消
}
  • 4.3 PostingThreadState怎么獲得?
    • ThreadLocal 是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類,通過(guò)它可以在指定的線程中存儲(chǔ)數(shù)據(jù),而這段數(shù)據(jù)是不會(huì)與其他線程共享的。
    • 可以看出currentPostingThreadState的實(shí)現(xiàn)是一個(gè)包含了PostingThreadState的ThreadLocal對(duì)象,這樣可以保證取到的都是自己線程對(duì)應(yīng)的數(shù)據(jù)。
    • 我們有了PostingThreadState獲取到了當(dāng)前線程的事件隊(duì)列,接下來(lái)就是事件分發(fā),我們來(lái)看postSingleEvent(eventQueue.remove(0), postingState);
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
    @Override
    protected PostingThreadState initialValue() {
        return new PostingThreadState();
    }
};
  • 4.4 來(lái)看看postSingleEvent方法里做了什么
    eventInheritance表示是否向上查找事件的父類,它的默認(rèn)值為true,可以通過(guò)在EventBusBuilder中來(lái)進(jìn)行配置。當(dāng)eventInheritance為true時(shí),則通過(guò)lookupAllEventTypes找到所有的父類事件并存在List中,然后通過(guò)postSingleEventForEventType方法對(duì)事件逐一處理,接下來(lái)看看postSingleEventForEventType方法
事件分發(fā)
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    //得到事件類型
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;

    //是否觸發(fā)訂閱了該事件(eventClass)的父類,以及接口的類的響應(yīng)方法.
    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) {
            Log.d(TAG, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}
  • 4.5 接下來(lái)看看postSingleEventForEventType方法
    同步取出該事件對(duì)應(yīng)的Subscription集合并遍歷該集合將事件event和對(duì)應(yīng)Subscription傳遞給postingState并調(diào)用postToSubscription方法對(duì)事件進(jìn)行處理,接下來(lái)看看postToSubscription方法:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
        //根據(jù)事件類型獲取所有的訂閱者
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    //向每個(gè)訂閱者分發(fā)事件
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
                //對(duì)事件進(jìn)行處理
                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;
}
  • 4.6 接下來(lái)看看postToSubscription方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING://默認(rèn)的 ThreadMode,表示在執(zhí)行 Post 操作的線程直接調(diào)用訂閱者的事件響應(yīng)方法,
        //不論該線程是否為主線程(UI 線程)。
            invokeSubscriber(subscription, event);
            break;
        case MAIN://在主線程中執(zhí)行響應(yīng)方法。
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BACKGROUND://在后臺(tái)線程中執(zhí)行響應(yīng)方法。
            if (isMainThread) {
                backgroundPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC://不論發(fā)布線程是否為主線程,都使用一個(gè)空閑線程來(lái)處理。
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
    }
}
  • 4.7 整個(gè)流程圖


    511825-20160330182550879-762466444.png
  • 4.8 總結(jié)一下整個(gè)事件分發(fā)的過(guò)程
    • 首先獲取當(dāng)前線程的PostingThreadState對(duì)象從而獲取到當(dāng)前線程的事件隊(duì)列
    • 通過(guò)事件類型獲取到所有訂閱者集合
    • 通過(guò)反射執(zhí)行訂閱者中的訂閱方法

5.EventBus取消注冊(cè)解析

  • 5.1 unregister(this)方法入手
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
    //獲取訂閱者的所有訂閱的事件類型
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            //從事件類型的訂閱者集合中移除訂閱者
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}
  • 5.2 再來(lái)看看unsubscribeByEventType(subscriber, eventType)
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--;
            }
        }
    }
}
  • 5.3 取消注冊(cè)流程圖


    Image.png
  • 5.4 總結(jié)一下取消注冊(cè)的過(guò)程
    • 1、首先獲取訂閱者的所有訂閱事件
    • 2、遍歷訂閱事件
    • 3、根據(jù)訂閱事件獲取所有的訂閱了該事件的訂閱者集合
    • 4、將該訂閱者移除
    • 5、將步驟1中的集合中的訂閱者移除

6.總結(jié)一下EventBus的工作原理

  • 6.1 訂閱邏輯
    • 1、首先用register()方法注冊(cè)一個(gè)訂閱者
    • 2、獲取該訂閱者的所有訂閱的方法
    • 3、根據(jù)該訂閱者的所有訂閱的事件類型,將訂閱者存入到每個(gè)以 事件類型為key 以所有訂閱者為values的map集合中
    • 4、然后將訂閱事件添加到以訂閱者為key 以訂閱者所有訂閱事件為values的map集合中
    • 5、如果是訂閱了粘滯事件的訂閱者,從粘滯事件緩存區(qū)獲取之前發(fā)送過(guò)的粘滯事件,響應(yīng)這些粘滯事件。
  • 6.2 事件發(fā)送邏輯
    • 1、首先獲取當(dāng)前線程的事件隊(duì)列
    • 2、將要發(fā)送的事件添加到事件隊(duì)列中
    • 3、根據(jù)發(fā)送事件類型獲取所有的訂閱者
    • 4、根據(jù)響應(yīng)方法的執(zhí)行模式,在相應(yīng)線程通過(guò)反射執(zhí)行訂閱者的訂閱方法
  • 6.3 取消邏輯
    • 1、首先通過(guò)unregister方法拿到要取消的訂閱者
    • 2、得到該訂閱者的所有訂閱事件類型
    • 3、遍歷事件類型,根據(jù)每個(gè)事件類型獲取到所有的訂閱者集合,并從集合中刪除該訂閱者
    • 4、將訂閱者從步驟2的集合中移除
  • 6.4 利與弊
    • EventBus好處比較明顯,它能夠解耦和,將業(yè)務(wù)和視圖分離,代碼實(shí)現(xiàn)比較容易。而且3.0后,我們可以通過(guò)apt預(yù)編譯找到訂閱者,避免了運(yùn)行期間的反射處理解析,大大提高了效率。當(dāng)然EventBus也會(huì)帶來(lái)一些隱患和弊端,如果濫用的話會(huì)導(dǎo)致邏輯的分散并造成維護(hù)起來(lái)的困難。另外大量采用EventBus代碼的可讀性也會(huì)變差。

7.其他介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評(píng)論 25 708
  • EventBus源碼分析(一) EventBus官方介紹為一個(gè)為Android系統(tǒng)優(yōu)化的事件訂閱總線,它不僅可以很...
    蕉下孤客閱讀 4,106評(píng)論 4 42
  • 我每周會(huì)寫一篇源代碼分析的文章,以后也可能會(huì)有其他主題.如果你喜歡我寫的文章的話,歡迎關(guān)注我的新浪微博@達(dá)達(dá)達(dá)達(dá)s...
    SkyKai閱讀 25,178評(píng)論 23 184
  • 這是日本繪本大師安野光雅唯一的人生隨筆,他用看似笨拙、幼稚的方法,生動(dòng)描繪了他對(duì)繪畫的喜愛(ài)、對(duì)夢(mèng)想的堅(jiān)持和對(duì)人生的...
    流年2016閱讀 809評(píng)論 0 0
  • 流水賬 上班陰天,下班中雨。媳婦放假第一天,睡得呼呼滴,好可愛(ài)!整第36周,快安全上岸了,保佑哦。風(fēng)平浪靜的一天:...
    貍貍的守護(hù)者閱讀 258評(píng)論 0 0

友情鏈接更多精彩內(nèi)容