<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發

      導航

      Android事件總線(四)源碼解析otto

      前言

      上一篇文章中講到了otto的用法,這一篇我們來講一下otto的源碼。可能有人覺得otto過時了,但是通過源碼我們學習的是高手設計otto時的設計理念,這種設計理念是不過時的。

      otto各個類的作用

      首先先來看一下otto的源碼的各個類的作用,如下圖所示。

      如圖所示,otto的源碼并不多,主要的類的功能如下:

      • Produce、Subscribe:發布者和訂閱者注解類。
      • Bus:事件總線類,用來注冊和取消注冊,維護發布-訂閱模型,并處理事件調度分發。
      • HandlerFinder、AnnotatedHandlerFinder:用來查找發布者和訂閱者。
      • EventProducer、EventHandler:分別封裝發布者和訂閱者的數據結構。

      otto構造函數

      在使用otto時,首先要創建Bus類,Bus類的構造函數如下所示。

      public Bus() {
          this(DEFAULT_IDENTIFIER);
      }
      View Code

      這個DEFAULT_IDENTIFIER是一個字符串”default”,this調用了Bus類的另一個構造函數:

      public Bus(String identifier) {
         this(ThreadEnforcer.MAIN, identifier);
       }
      View Code

      ThreadEnforcer.MAIN意味著默認在主線程中調度事件,再往里看this又調用了什么,如下所示。

      public Bus(ThreadEnforcer enforcer, String identifier) {
        this(enforcer, identifier, HandlerFinder.ANNOTATED);
      }
      View Code

      第一個參數我們提到了,就是事件調度的簡稱,identifier為Bus的名稱,默認為”default”。而identifier則是HandlerFinder,用于在register、unregister的時候尋找所有的subscriber和producer。再往里查看this又調用了什么,如下所示。

      Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder) {
        this.enforcer =  enforcer;
        this.identifier = identifier;
        this.handlerFinder = handlerFinder;
      }
      View Code

      這個是最終調用的Bus的構造函數,在這里要首先記住handlerFinder 指的就是傳進來的HandlerFinder.ANNOTATED,后面在注冊時會用到handlerFinder這個屬性。

      注冊

      生成bus類后,我們要調用它的register方法來進行注冊。register方法如下所示。

      public void register(Object object) {
          if (object == null) {
            throw new NullPointerException("Object to register must not be null.");
          }
          enforcer.enforce(this);
          Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);//1
      ...
      }
      View Code

      注釋1出調用了handlerFinder的findAllProducers方法,此前講到構造函數時,我們知道這個handlerFinder指的是HandlerFinder.ANNOTATED,ANNOTATED的代碼如下所示。

      HandlerFinder ANNOTATED = new HandlerFinder() {
         @Override
         public Map<Class<?>, EventProducer> findAllProducers(Object listener) {
           return AnnotatedHandlerFinder.findAllProducers(listener);
         }
         @Override
         public Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
           return AnnotatedHandlerFinder.findAllSubscribers(listener);
         }
       };
      View Code

      從上面的代碼的findAllProducers方法和findAllSubscribers方法的返回值可以推斷出一個注冊類只能有一個發布者,卻可以有多個訂閱者。findAllProducers方法最終調用的是AnnotatedHandlerFinder的findAllProducers方法:

      static Map<Class<?>, EventProducer> findAllProducers(Object listener) {
        final Class<?> listenerClass = listener.getClass();
        Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();
        Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);//1
        if (null == methods) {
          methods = new HashMap<Class<?>, Method>();
          loadAnnotatedProducerMethods(listenerClass, methods);//2
        }
        if (!methods.isEmpty()) {
          for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {//3
            EventProducer producer = new EventProducer(listener, e.getValue());
            handlersInMethod.put(e.getKey(), producer);
          }
        }
        return handlersInMethod;
      }
      View Code

      PRODUCERS_CACHE是一個ConcurrentHashMap,它的key為bus.register()時傳入的class,而value是一個map,這個map的key是事件的class,value是生產事件的方法。注釋1處首先在PRODUCERS_CACHE根據傳入的對象的類型查找是否有緩存的事件方法,如果沒有就調用注釋2處的代碼利用反射去尋找所有使用了@Produce注解的方法,并且將結果緩存到PRODUCERS_CACHE中。接著在注釋3處遍歷這些事件方法,并為每個事件方法創建了EventProducer類,并將這些EventProducer類作為value存入handlersInMethod并返回。接下來我們返回register方法。如下所示。

      public void register(Object object) {
        if (object == null) {
          throw new NullPointerException("Object to register must not be null.");
        }
        enforcer.enforce(this);
        Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
        for (Class<?> type : foundProducers.keySet()) {
          final EventProducer producer = foundProducers.get(type);
          EventProducer previousProducer = producersByType.putIfAbsent(type, producer);//1
          if (previousProducer != null) {
            throw new IllegalArgumentException("Producer method for type " + type
              + " found on type " + producer.target.getClass()
              + ", but already registered by type " + previousProducer.target.getClass() + ".");
          }
          Set<EventHandler> handlers = handlersByType.get(type);
          if (handlers != null && !handlers.isEmpty()) {
            for (EventHandler handler : handlers) {
              dispatchProducerResultToHandler(handler, producer);//2
            }
          }
        }
        ...
      }
      View Code

      調用完findAllProducers方法后,會在注釋1處檢查是否有該類型的發布者已經存在,如果存在則拋出異常,不存在則調用注釋2處的dispatchProducerResultToHandler方法來觸發和發布者對應的訂閱者來處理事件。接下來register方法的后一部分代碼就不帖上來了,跟此前的流程大致一樣就是調用findAllSubscribers方法來查找所有使用了@Subscribe注解的方法,跟此前不同的是一個注冊類可以有多個訂閱者,接下來判斷是否有該類型的訂閱者存在,也就是判斷注冊類是否已經注冊,如果存在則拋出異常,不存在則查找是否有和這些訂閱者對應的發布者,如果有的話,就會觸發對應的訂閱者處理事件。

      發送事件

      我們會調用Bus的post方法來發送事件,它的代碼如下所示。

      public void post(Object event) {
        if (event == null) {
          throw new NullPointerException("Event to post must not be null.");
        }
        enforcer.enforce(this);
        Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());//1
        boolean dispatched = false;
        for (Class<?> eventType : dispatchTypes) {
          Set<EventHandler> wrappers = getHandlersForEventType(eventType);
          if (wrappers != null && !wrappers.isEmpty()) {
            dispatched = true;
            for (EventHandler wrapper : wrappers) {
              enqueueEvent(event, wrapper);//2
            }
          }
        }
        if (!dispatched && !(event instanceof DeadEvent)) {
          post(new DeadEvent(this, event));
        }
        dispatchQueuedEvents();//3
      }
      View Code

      注釋1處的flattenHierarchy方法首先會從緩存中查找傳進來的event(消息事件類)的所有父類,如果沒有則找到event的所有父類并存儲入緩存中。接下來遍歷這些父類找到它們的所有訂閱者,并在注釋2處將這些訂閱者壓入線程的事件隊列中。并在注釋3處調用dispatchQueuedEvents方法依次取出事件隊列中的訂閱者來處理相應event的事件。

      取消注冊

      取消注冊時,我們會調用Bus的unregister方法,unregister方法如下所示。

      public void unregister(Object object) {
        if (object == null) {
          throw new NullPointerException("Object to unregister must not be null.");
        }
        enforcer.enforce(this);
        Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);//1
        for (Map.Entry<Class<?>, EventProducer> entry : producersInListener.entrySet()) {
          final Class<?> key = entry.getKey();
          EventProducer producer = getProducerForEventType(key);
          EventProducer value = entry.getValue();
          if (value == null || !value.equals(producer)) {
            throw new IllegalArgumentException(
                "Missing event producer for an annotated method. Is " + object.getClass()
                    + " registered?");
          }
          producersByType.remove(key).invalidate();//2
        }
      ...
      }
      View Code

      取消注冊分為兩部分,一部分是訂閱者取消注冊,另一部分是發布者取消注冊。這兩部分的代碼類似,因此,上面的代碼只列出了發布者取消注冊的代碼。在注釋1處得到所有使用@Produce注解的方法,并遍歷這些方法,調用注釋2處的代碼從緩存中清除所有和傳進來的注冊類相關的發布者,來完成發布者的取消注冊操作。

      posted on 2016-11-13 02:39  安卓筆記俠  閱讀(539)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 久久精品蜜芽亚洲国产AV| 在线观看免费网页欧美成| 成在线人永久免费视频播放| 中文字幕日韩有码av| 精人妻无码一区二区三区| 久草热在线视频免费播放| 国产永久免费高清在线| 菏泽市| 精品人妻中文无码av在线| 日本欧美一区二区三区在线播放| 高清无码午夜福利视频| 亚洲无av中文字幕在线| 午夜福利精品国产二区| 欧美大屁股xxxx高跟欧美黑人| 天干天干啦夜天干天2017| 日韩中文字幕人妻一区| 亚洲国产精品久久久久婷婷老年| 国产蜜臀av在线一区二区| 制服 丝袜 亚洲 中文 综合| 少妇精品导航| 国产日产亚洲系列av| 久久精品国产91精品亚洲| 国产精品一区在线蜜臀| 久久精品岛国AV一区二区无码| 一卡二卡三卡四卡视频区| 一区二区三区黄色一级片| 一本色道久久88精品综合| 香蕉EEWW99国产精选免费| 国产综合av一区二区三区| 日韩精品无码一区二区视频 | 亚洲精品精华液一区二区| 日本55丰满熟妇厨房伦| 色窝窝免费一区二区三区| 国产亚洲精品久久久久久青梅 | 亚洲日本va午夜中文字幕久久 | 国产精品最新免费视频| 亚洲永久精品ww47永久入口| 午夜av高清在线观看| 亚洲高清免费在线观看| 粉嫩一区二区三区国产精品| 精品国产迷系列在线观看|