otto源碼分析,otto源碼

來源:互聯網
上載者:User

otto源碼分析,otto源碼
otto這個開源項目是一個event bus模式的訊息架構,用於程式各個模組之間的通訊,此訊息架構可以使得各個
模組之間減少耦合性。

此項目是支付公司square一個開源項目,項目託管於github
https://github.com/square/otto


基本模型是,Android的組件可以註冊監聽,然後發送訊息,接收訊息,模式就是觀察者模式,但是有別於
java實現的觀察者模式,otto更具解耦性,通過註解可以現實監聽工作。

otto中的總控制中心的類是Bus,複雜事件的註冊分發工作。

首先要把需要把監聽事件的組件或者發送事件的組件註冊進去
調用Bus的register方法
publicvoidregister(Object object) 

這個方法的解釋是這樣的,先看下英文

/**   * Registers all handler methods on {@code object} to receive events and producer methods to provide events.   * If any subscribers are registering for types which already have a producer they will be called immediately   * with the result of calling that producer.   * If any producers are registering for types which already have subscribers, each subscriber will be called with   * the value from the result of calling the producer.   *   * @param object object whose handler methods should be registered.   * @throws NullPointerException if the object is null.   */

參數這個對象的所有的事件處理方法(訂閱者法)用於處理接受到的事件,生產者方法用於提供事件。
意思是說,這個註冊者即可以接收事件,也可以生產事件。
接著說了註冊時的一些特殊情況,
(1)如果在註冊的時候,訂閱了一個事件類型,並且有產生事件的方法,那麼會立即調用產生事件的方法,
把事件分發給這個訂閱者方法。
(2)如果在註冊的時候,產生特定事件的方法已經存在了訂閱者,會呼叫事件產生方法,把事件分發給事件
訂閱者。
方法的具體實現分析:

public void register(Object object) {    if (object == null) {      throw new NullPointerException("Object to register must not be null.");    }    //檢查是否在主線程中進行了註冊的,預設必須在主線程中調用    enforcer.enforce(this);       //key是事件的class對象    Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);

上面的代碼用於擷取這個被註冊對象的所有生產者方法,可以對應於多個事件的生產者方法
           一個被註冊對象,同一個事件只能註冊一個生產者方法。
 
handlerFinder是HandlerFinder的執行個體,是Bus的輔助類,用於找到指定被註冊者的所有生產者和訂閱者方法。
handlerFinder.findAllProducers(object)返回一個map集合,key是事件的Class的執行個體,value
是EventProducer是對生產者方法和被註冊者執行個體的封裝。

從這裡可以看出,雖然沒有繼續看這個方法的代碼,可以猜測被註冊者對於同一個事件只能有一個生產者。
我們繼續跟蹤HandlerFinder findAllProducers()方法的代碼
HandlerFinder只是一個借口,然後在其內部實現了一個內部類
如下:

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

會調用到這句代碼:
AnnotatedHandlerFinder.findAllProducers(listener)

進去看下代碼

static Map<Class<?>, EventProducer> findAllProducers(Object listener) {    final Class<?> listenerClass = listener.getClass();    Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();     //檢查是否不存在此listenerClass的生產者方法,需要找出來放到PRODUCERS_CACHE中     //PRODUCERS_CACHE是一個map,可以是listener的class對象,值是所有的事件生產者方法    if (!PRODUCERS_CACHE.containsKey(listenerClass)) {      loadAnnotatedMethods(listenerClass);    }//下面的代碼就是把所有的生產者方法封裝起來,返回給調用者    Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);    if (!methods.isEmpty()) {      for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {        EventProducer producer = new EventProducer(listener, e.getValue());        handlersInMethod.put(e.getKey(), producer);      }    }    return handlersInMethod;  }

我們再回到Bus的register方法

//key是事件的class對象    Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);    for (Class<?> type : foundProducers.keySet()) {               //下面幾行代碼用來檢查,事件是否已經註冊過了,一個類一個事件只能註冊一次      final EventProducer producer = foundProducers.get(type);      EventProducer previousProducer = producersByType.putIfAbsent(type, producer);      //checking if the previous producer existed      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);        }      }    }
這行代碼用於回調
dispatchProducerResultToHandler(handler, producer);
具體實現就是通過反射去調用producer生產出方事件,把事件傳遞給handler,再通過反射
回調註冊的方法。

繼續。。。

//如果有處理此事件的註冊者,回調註冊者    Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);    for (Class<?> type : foundHandlersMap.keySet()) {    //type變數是事件的class對象      Set<EventHandler> handlers = handlersByType.get(type);      if (handlers == null) {        //concurrent put if absent        Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();        handlers = handlersByType.putIfAbsent(type, handlersCreation);        if (handlers == null) {            handlers = handlersCreation;        }      }      final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);      handlers.addAll(foundHandlers);    }

regeister這個方法解釋完了。

在繼續看下post(event)方法
這個方法的作用是分發事件到所有註冊這個事件的方法
有可能這個事件分發失敗,會封裝一個DeadEvent對象,然後重新分發,但是這個DeadEvent對象沒有被處理。。。

public void post(Object event) {    if (event == null) {      throw new NullPointerException("Event to post must not be null.");    }    enforcer.enforce(this);    //返回這個event的所有繼承關係鏈的所有class對象(父類class對象和自己)    Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());    //對event家族的所有類的相關註冊方法進行調用    boolean dispatched = false;    for (Class<?> eventType : dispatchTypes) {    //獲得和eventType相關的所有註冊方法      Set<EventHandler> wrappers = getHandlersForEventType(eventType);      //把需要回調處理的註冊方法的封裝類塞進當前線程處理的隊列中去      if (wrappers != null && !wrappers.isEmpty()) {        dispatched = true;        for (EventHandler wrapper : wrappers) {          enqueueEvent(event, wrapper);        }      }    }    //沒處理的,再分發一次,但是沒有發現再次處理的邏輯    if (!dispatched && !(event instanceof DeadEvent)) {      post(new DeadEvent(this, event));    }    dispatchQueuedEvents();  }

接下來就是登出方法unregister(listener)
刪除和這個listener對象相關的生產事件的方法和註冊監聽的方法

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);    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();    }    //返回當前對象的所有註冊的方法,置為無效並刪除掉    Map<Class<?>, Set<EventHandler>> handlersInListener = handlerFinder.findAllSubscribers(object);    for (Map.Entry<Class<?>, Set<EventHandler>> entry : handlersInListener.entrySet()) {    //返回對應event的所有註冊方法的封裝類      Set<EventHandler> currentHandlers = getHandlersForEventType(entry.getKey());      Collection<EventHandler> eventMethodsInListener = entry.getValue();      if (currentHandlers == null || !currentHandlers.containsAll(eventMethodsInListener)) {        throw new IllegalArgumentException(            "Missing event handler for an annotated method. Is " + object.getClass()                + " registered?");      }      for (EventHandler handler : currentHandlers) {        if (eventMethodsInListener.contains(handler)) {          handler.invalidate();        }      }      currentHandlers.removeAll(eventMethodsInListener);    }  }
最後總結一下,
(1)同一個事件只能有一個生產此事件的方法,如果存在多個會報非檢查異常,產生此類事件的只允許有一個來源或者說只允許
有一個活者的來源。
(2)同一個事件可以有多個註冊監聽同一個事件的方法,只要存在就會分發給他們。
(3)按照官方的demo盡量只有一個Bus執行個體,一是減少記憶體消耗,也利於分發工作,如果不同的Bus,那麼就無法把分發給其他Bus的註冊監聽的方法了。

這個EventBus訊息架構比較適合推送的處理中心對訊息的分發工作,可以解耦的方式,分發給程式的各個模組。

square公司還有很多比較好的開源項目,
網路程式庫okhttp初支援http外,還支援spdy,github地址 https://github.com/square/okhttp
處理圖片的庫picasso(畢加索) ,github地址  https://github.com/square/picasso
一個日曆控制項陳列庫,包含Android版和iOS版, github地址  https://github.com/square/android-times-square (Android版)。
其它square公司的開源項目: https://github.com/square





怎分析網站原始碼

這個看網頁的難易,互動式網頁的話(如用ASP編的)你就的熟悉程式設計語言,如果是CSS編寫的話,就得熟悉CSS。至於一些糅合製作的網頁就是高難度了 ,我也不是太精
 
c++ 源碼 分析?

這麼說,你一定有c++的基礎了,那麼我推薦一本書給你
侯俊傑的 《slt源碼分析》。stl不用說,那可是精品,都作為標準了。

這本書是很好,但是要求基本也比較高的。

不知道誰說過一句話:什麼樣的書固然沒什麼用處,但是對於特別的人,特別的時間,將會特別的有用!

還有源碼好多了,你可以看一下一些c++的論壇上面會後好多代碼的,但是品質不值得保證!
個人認為既然是想提高水平,就要看一些精品。不管起點要求多高,因為這條路終究要走下去的!!

僅是建議!
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.