<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] EventBus 是 Android 平臺非常優秀的事件總線開源庫,來自于德國的 greenrobot 團隊,該團隊旗下還有大名鼎鼎的 greenDAO。EventBus 足夠快速、輕量,安裝量超過 100,000,000+!足以看出其熱門程度。本文是我對 EventBus 3.0 的源碼分析,源碼分析經驗不足,如有錯誤,還請指出。 # 觀察者模式 本段引自[圖說設計模式](http://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html#id6) ## 模式動機 建立一種對象與對象之間的依賴關系,一個對象發生改變時將自動通知其他對象,其他對象將相應做出反應。在此,發生改變的對象稱為觀察目標,而被通知的對象稱為觀察者,一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯系,可以根據需要增加和刪除觀察者,使得系統更易于擴展,這就是觀察者模式的模式動機。 ## 模式定義 觀察者模式(Observer Pattern):定義對象間的一種一對多依賴關系,使得每當一個對象狀態發生改變時,其相關依賴對象皆得到通知并被自動更新。觀察者模式又叫做發布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。 觀察者模式是一種對象行為型模式。 ## 實現總結 具體代碼實現可參考 [我的個人 wiki](http://wiki.xuchongyang.com/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F.html) * 觀察目標會維護一個觀察者的集合,并提供新增、刪除接口 * 當觀察目標需要通知觀察者時,會循環調用觀察者集合元素的更新方法,并可將部分參數或觀察目標自身傳遞給觀察者 * 觀察者更新方法被調用后,可根據傳遞來的數據做相應的處理 ## 優點 * 觀察者模式可以實現表示層和數據邏輯層的分離,并定義了穩定的消息更新傳遞機制,抽象了更新接口,使得可以有各種各樣不同的表示層作為具體觀察者角色。 * 觀察者模式在觀察目標和觀察者之間建立一個抽象的耦合。 * 觀察者模式支持廣播通信。 * 觀察者模式符合“開閉原則”的要求。 ## 缺點 * 如果一個觀察目標對象有很多直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。 * 如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。 * 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎么發生變化的,而僅僅只是知道觀察目標發生了變化。 # EventBus 3.0源碼分析 ## 簡單使用 EventBus 3.0 的使用非常簡單,總共 4 步: * 定義事件 ```java public static class MessageEvent { /* Additional fields if needed */ } ``` * 構建觀察者,聲明欲觀察事件 ```java @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {/* Do something */}; ``` * 建立觀察者、觀察目標關系 ```java @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } ``` * 觀察目標發送事件 ```java EventBus.getDefault().post(new MessageEvent()); ``` ## 整體設計 ![](https://ws2.sinaimg.cn/large/006tKfTcgy1fkuqqvweilj30zk0db74s.jpg) 一目了然!接下來我們按使用步驟來一一分析。 ## register 注冊 ```java public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); // 根據觀察者類型找出該觀察者的所有事件訂閱方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { // 給觀察者訂閱每個事件 subscribe(subscriber, subscriberMethod); } } } ``` register 方法的作用就很清楚了,一一來看: 1、首先來看 findSubscriberMethods 方法的實現 ```java List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { // 先從方法緩存中查找是否有緩存 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } if (ignoreGeneratedIndex) { // 通過反射來獲取訂閱方法 subscriberMethods = findUsingReflection(subscriberClass); } else { // 通過 Index 來獲取訂閱方法,這個是在 EventBus 3.0 中新添加的,后面再詳細分析 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; } } ``` 我們的觀察者訂閱目標事件,都是通過 Subscribe 注解來訂閱的。看下 Subscribe 注解的聲明: ```java @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { ThreadMode threadMode() default ThreadMode.POSTING; boolean sticky() default false; int priority() default 0; } ``` 可以看到該注解的保留時長為 RUNTIME,所以可以在運行時通過反射讀取到注解中的信息。同時,EventBus 3.0 新增了一個 EventBusAnnotationProcessor 注解處理器,在編譯期讀取注解并解析,然后通過 java 類保存所有觀察者訂閱的信息,運行時直接使用,這樣會比在運行時通過反射獲取觀察者的訂閱信息來的快。 2、register 中的 subscribe 方法 先看 EventBus 類的三個成員變量,后面會用到。 ```java // 鍵:事件類型,值:訂閱關系集合 private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; // 鍵:觀察者,值:訂閱事件集合 private final Map<Object, List<Class<?>>> typesBySubscriber; // 鍵:粘性事件的 class 對象,值:事件對象 private final Map<Class<?>, Object> stickyEvents; ``` ```java // Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; // 建立訂閱關系,便于后面取消訂閱 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 根據事件類型獲取訂閱關系 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(); // 根據優先級將當前訂閱關系插入到 subscriptions 中 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); } } } ``` 上面 checkPostStickyEventToSubscription 的實現如下: ```java private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) { if (stickyEvent != null) { // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state) // --> Strange corner case, which we don't take care of here. postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper()); } } ``` postToSubscription 我們在后面事件分發中還會見到,再詳細看。 ## post 分發事件 event ```java /** Posts the given event to the event bus. */ public void post(Object event) { // 獲得當前線程的 PostingThreadState PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue; // 將當前事件添加到當前線程的事件隊列中 eventQueue.add(event); if (!postingState.isPosting) { 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()) { // 發送單個事件 postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } } ``` post 方法的關鍵代碼在 postSingleEvent: ```java 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) { Log.d(TAG, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } } ``` 其中 postSingleEventForEventType 方法如下: ```java private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { // 根據事件 class 類型來找出所有訂閱該事件的訂閱關系 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 方法如下: ```java 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 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 進行判斷,再根據發布線程情況 invoke 觀察者的訂閱方法。 ThreadMode 總共有四類: 本段引自[EventBus 源碼解析](http://a.codekk.com/detail/Android/Trinea/EventBus%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90) * PostThread:默認的 ThreadMode,表示在執行 Post 操作的線程直接調用訂閱者的事件響應方法,不論該線程是否為主線程(UI 線程)。當該線程為主線程時,響應方法中不能有耗時操作,否則有卡主線程的風險。適用場景:對于是否在主線程執行無要求,但若 Post 線程為主線程,不能耗時的操作; * MainThread:在主線程中執行響應方法。如果發布線程就是主線程,則直接調用訂閱者的事件響應方法,否則通過主線程的 Handler 發送消息在主線程中處理——調用訂閱者的事件響應函數。顯然,MainThread 類的方法也不能有耗時操作,以避免卡主線程。適用場景:必須在主線程執行的操作; * BackgroundThread:在后臺線程中執行響應方法。如果發布線程不是主線程,則直接調用訂閱者的事件響應函數,否則啟動唯一的后臺線程去處理。由于后臺線程是唯一的,當事件超過一個的時候,它們會被放在隊列中依次執行,因此該類響應方法雖然沒有 PostThread 類和 MainThread 類方法對性能敏感,但最好不要有重度耗時的操作或太頻繁的輕度耗時操作,以造成其他操作等待。適用場景:操作輕微耗時且不會過于頻繁,即一般的耗時操作都可以放在這里; * Async:不論發布線程是否為主線程,都使用一個空閑線程來處理。和 BackgroundThread 不同的是,Async 類的所有線程是相互獨立的,因此不會出現卡線程的問題。適用場景:長耗時操作,例如網絡訪問。 接著來看下 invokeSubscriber 方法。 ```java void invokeSubscriber(Subscription subscription, Object event) { try { //通過反射調用了觀察者的訂閱函數,并把 event 對象作為參數傳入 subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } } ``` ## unregister 解除注冊 ```java /** 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()); } } ``` 看關鍵的 unsubscribeByEventType 方法: ```java /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ 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--; } } } } ``` # EventBus 源碼分析概覽 1、register 方法注冊:首先會根據觀察者的類型找出它聲明要訂閱的所有事件(訂閱方法),然后一一訂閱 2、訂閱過程:首先根據事件類型獲取到訂閱該事件類型的訂閱關系集合,(為觀察者和訂閱方法生成訂閱關系)并把這個訂閱關系對象存入到該集合中;然后根據觀察者獲取到該觀察者訂閱的事件集合,并把當前訂閱的事件放入到事件集合中。 EventBus 有兩個 Map 類型的成員變量,分別為: * Map1 用于根據事件類型通過反射調用觀察者的方法 -- Key:事件類型,Value:訂閱了該事件的訂閱關系(觀察者、訂閱方法)集合 * Map2 用于取消訂閱 -- Key:觀察者,Value:該觀察者的訂閱事件集合 3、觀察目標 post 事件:首先獲得當前線程的待發送事件隊列,并把當前事件對象添加進去;接著依次發送當前隊列中的事件對象。 4、事件對象的發送:首先從剛才的 Map 中,根據事件類型取得訂閱關系集合;然后遍歷訂閱關系集合,先進行線程判斷,再分別通過反射調用觀察者的訂閱方法 5、unregister 解除注冊:首先從 Map2 中根據觀察者取得該觀察者訂閱事件集合,然后一一解除該觀察者和每個事件的訂閱關系,最后再把該觀察者從 Map2 中刪除 6、解除觀察者和每個事件的訂閱關系:從 Map1 中根據事件類型獲得訂閱了該事件的訂閱關系集合,將該觀察者相關的訂閱關系進行刪除 補充: * 訂閱方法是對訂閱事件做的一層封裝 * 訂閱關系是對觀察者和訂閱方法做的一層封裝 另分享一篇分析思路不錯的文章 [淺析EventBus 3.0實現思想](http://alighters.com/blog/2016/05/22/eventbus3-dot-0-analyze/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看