自己眼中的EventBus

項(xiàng)目上線有一段時(shí)間了,自己總結(jié)了下項(xiàng)目。項(xiàng)目中的EventBus真的是到處都有它的影子,說實(shí)話,用上EventBus后,個(gè)人覺得項(xiàng)目中的業(yè)務(wù)變得很輕松,不用考慮哪個(gè)類發(fā)的,哪個(gè)類去回調(diào)。別人都說EventBus是一個(gè)"事務(wù)總線",就像一個(gè)公司的項(xiàng)目小組一樣。項(xiàng)目經(jīng)理給各個(gè)模塊的分配好任務(wù)了,然后各人模塊的人員處理自己的事情,最后完成整個(gè)事務(wù)。

Bus類:

public class Bus {   
     static volatile Bus sInstance;   
     Finder mFinder;   
     //CopyOnWriteArrayList一般用在讀和寫同時(shí)存在的情況下使用    
     Map<Class<?>, CopyOnWriteArrayList<Subscriber>> mSubscriberMap;    
     PostHandler mPostHandler; 
     private Bus() {      
         mFinder = new NameBasedFinder();  
         mSubscriberMap = new HashMap<>();    
         mPostHandler = new PostHandler(Looper.getMainLooper(), this);  
     }   
     /**   
      * 得到一個(gè)單例的上下文對(duì)象 
      * @return  
     */    
     public static Bus getDefault() {    
        if (sInstance == null) {            
             synchronized (Bus.class) {          
                  if (sInstance == null) {            
                      sInstance = new Bus();       
                  }           
             }    
         }      
         return sInstance;    
      }  

      public void register(Object subscriber) {    
          /**       
           * 找到該類下面的所有以onEvent開頭的方法   
           */       
          List<Method> methods = mFinder.findSubscriber(subscriber.getClass());     
          if (methods == null || methods.size() < 1) {     
             return;   
          }     
          CopyOnWriteArrayList<Subscriber> subscribers = mSubscriberMap.get(subscriber.getClass());     
          if (subscribers == null) {       
             subscribers = new CopyOnWriteArrayList<>();    
             /**          
              * 該map用來存儲(chǔ)onevent開頭的方法的第一個(gè)參數(shù)為key和          
              * subscribers的集合          
              */        
             mSubscriberMap.put(methods.get(0).getParameterTypes()[0], subscribers);   
          }     
          for (Method method : methods) {      
            /**            
             * 封裝了該類和該類帶有onevent的方法  
             */          
             Subscriber newSubscriber = new Subscriber(subscriber, method);       
             subscribers.add(newSubscriber);   
          }   
      }    

      public void unregister(Object subscriber) {       
         CopyOnWriteArrayList<Subscriber> subscribers = mSubscriberMap.remove(subscriber.getClass());  
         if (subscribers != null) {        
            for (Subscriber s : subscribers) {       
               s.mMethod = null;             
               s.mSubscriber = null;       
            }    
         }   
      } 

      public void post(Object event) {       
        //TODO post with handler      
        mPostHandler.enqueue(event);  
      }
}

Bus類主要是消息的注冊(cè)、發(fā)送、注銷幾個(gè)動(dòng)作。
在注冊(cè)中,首先找到要注冊(cè)類中onEvent方法,這里是怎么做到的呢。大家找找成員變量mFinder是怎么生成的。其實(shí)它是一個(gè)接口:

public interface Finder {   
    List<Method> findSubscriber(Class<?> subscriber);
}

再來看看它的實(shí)現(xiàn)類吧:


實(shí)現(xiàn)類.png
public class NameBasedFinder implements Finder {    
   /**     
    * public Method[] getMethods()返回某個(gè)類的所有公用(public)方法包括其繼承類的公用方法,當(dāng)然也包括它所實(shí)現(xiàn)接口的方法。   
      public Method[] getDeclaredMethods()返回自身類的所有公用(public)方法包括私有(private)方法,但包括其繼承類的方法,當(dāng)然也包括它所實(shí)現(xiàn)接口的方法。   
    * 找到某個(gè)類的所有的    
    * @param subscriber     
    * @return  
    */   
    @Override 
    public List<Method> findSubscriber(Class<?> subscriber) {       
       List<Method> methods = new ArrayList<>(); 
       for (Method method : subscriber.getDeclaredMethods()) {   
           if (method.getName().startsWith("onEvent") && 
              method.getParameterTypes().length == 1) {                
              methods.add(method);                
           }   
       }     
       return methods; 
    }
}

看到了沒,該實(shí)現(xiàn)類只是簡(jiǎn)單地將onEvent開頭的方法給封裝到一個(gè)集合里面去了。
接著看注冊(cè)里面,獲取到以onEvent開頭的方法后,將該method集合添加到一個(gè)mSubscriberMap中,該map中的key就是onEvent開頭的方法的第一個(gè)參數(shù),value就是Subscriber的集合。
那就再來看看Subscriber類吧:

public class Subscriber {    
   Object mSubscriber;    
   Method mMethod;   
   Class<?> mEventType; 
   public Subscriber(Object subscriber, Method method) {        
      mSubscriber = subscriber;    
      mMethod = method;   
     mEventType = method.getParameterTypes()[0];  
   }
}

該類有三個(gè)成員變量,可能現(xiàn)在有人不知道為啥要這么定義,到了后面用到的時(shí)候就知道為啥這么定義了。
好了,整個(gè)注冊(cè)的過程就這樣,最終的目的就是得到一個(gè)map對(duì)象。
下面來看看發(fā)送的過程吧:
mPostHandler.enqueue(event);
就這一行代碼,下面就看看mPostHandler類是怎么得來的吧。
mPostHandler = new PostHandler(Looper.getMainLooper(), this);
下面來看看PostHandler類吧:

public class PostHandler extends Handler {  
  final Bus mBus;   
  public PostHandler(Looper looper, Bus bus) {        
    super(looper);    
    mBus = bus; 
  }  
  @Override  
  public void handleMessage(Message msg) {        
    CopyOnWriteArrayList<Subscriber> subscribers = mBus.mSubscriberMap.get(msg.obj.getClass()); 
       for (Subscriber subscriber : subscribers) {            
          subscriber.mMethod.setAccessible(true);      
          try {           
              /**           
               * 第二個(gè)參數(shù)是方法的參數(shù),第-個(gè)參數(shù)是該類的對(duì)象                 
               */                
              subscriber.mMethod.invoke(subscriber.mSubscriber, msg.obj);     
          } catch (Exception e) {    
             e.printStackTrace();      
          }      
       }  
  }  

  void enqueue(Object event) {   
     Message message = obtainMessage();    
     message.obj = event;    
     sendMessage(message);   
  } 

}

看到該類了沒,還是逃不過handler通過handleMessage方法來接收處理消息了,這個(gè)地方就是核心的地方了。這里實(shí)際上bus類的post方法的參數(shù)就是這里的bus類中mSubscriberMap的key了,通過該key可以獲取到mSubscriberMap中的value值了,也就是Subscriber集合了,現(xiàn)在知道Subscriber類的定義了吧,mMethod是方法名,mSubscriber是該類對(duì)象,實(shí)際上它的第三個(gè)成員變量沒用到。最后通過反射來調(diào)用onEvent開頭的方法,整個(gè)過程就這么簡(jiǎn)單,是不是現(xiàn)在一目了然了呢。
最后就是注銷了:

public void unregister(Object subscriber) {       
   CopyOnWriteArrayList<Subscriber> subscribers = mSubscriberMap.remove(subscriber.getClass());  
   if (subscribers != null) {        
        for (Subscriber s : subscribers) {       
            s.mMethod = null;             
            s.mSubscriber = null;       
        }    
    }   
} 

這里沒什么好說的吧,就是將map中的對(duì)象給至空了。
好了,整個(gè)過程就這樣了,是不是幾個(gè)過程都清楚了。

下面用一個(gè)demo來測(cè)試該事例吧:

demo.gif

整個(gè)的內(nèi)容就這么多了,完全是靠自己的理解。如果有什么說得不清楚的地方,還需大家指出來。

借鑒的項(xiàng)目:https://github.com/avenwu/support

關(guān)于我:

email:a1002326270@163.com
github:enter

最后編輯于
?著作權(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)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • 項(xiàng)目到了一定階段會(huì)出現(xiàn)一種甜蜜的負(fù)擔(dān):業(yè)務(wù)的不斷發(fā)展與人員的流動(dòng)性越來越大,代碼維護(hù)與測(cè)試回歸流程越來越繁瑣。這個(gè)...
    fdacc6a1e764閱讀 3,332評(píng)論 0 6
  • 我每周會(huì)寫一篇源代碼分析的文章,以后也可能會(huì)有其他主題.如果你喜歡我寫的文章的話,歡迎關(guān)注我的新浪微博@達(dá)達(dá)達(dá)達(dá)s...
    SkyKai閱讀 25,172評(píng)論 23 184
  • 對(duì)于Android開發(fā)老司機(jī)來說肯定不會(huì)陌生,它是一個(gè)基于觀察者模式的事件發(fā)布/訂閱框架,開發(fā)者可以通過極少的代碼...
    飛揚(yáng)小米閱讀 1,544評(píng)論 0 50
  • 有一個(gè)同學(xué)和我說了一件事,覺得可以作為日記素材,就寫出來了。 一個(gè)客戶的房子需要裝修,他得到了兩個(gè)報(bào)價(jià),熟人報(bào)價(jià)是...
    安梓閱讀 545評(píng)論 0 1

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