自己眼中的EventBus

项目上线有一段时间了,自己总结了下项目。项目中的EventBus真的是到处都有它的影子,说实话,用上EventBus后,个人觉得项目中的业务变得很轻松,不用考虑哪个类发的,哪个类去回调。别人都说EventBus是一个"事务总线",就像一个公司的项目小组一样。项目经理给各个模块的分配好任务了,然后各人模块的人员处理自己的事情,最后完成整个事务。

Bus类:

public class Bus {   
     static volatile Bus sInstance;   
     Finder mFinder;   
     //CopyOnWriteArrayList一般用在读和写同时存在的情况下使用    
     Map<Class<?>, CopyOnWriteArrayList<Subscriber>> mSubscriberMap;    
     PostHandler mPostHandler; 
     private Bus() {      
         mFinder = new NameBasedFinder();  
         mSubscriberMap = new HashMap<>();    
         mPostHandler = new PostHandler(Looper.getMainLooper(), this);  
     }   
     /**   
      * 得到一个单例的上下文对象 
      * @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用来存储onevent开头的方法的第一个参数为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类主要是消息的注册、发送、注销几个动作。
在注册中,首先找到要注册类中onEvent方法,这里是怎么做到的呢。大家找找成员变量mFinder是怎么生成的。其实它是一个接口:

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

再来看看它的实现类吧:


实现类.png
public class NameBasedFinder implements Finder {    
   /**     
    * public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。   
      public Method[] getDeclaredMethods()返回自身类的所有公用(public)方法包括私有(private)方法,但包括其继承类的方法,当然也包括它所实现接口的方法。   
    * 找到某个类的所有的    
    * @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; 
    }
}

看到了没,该实现类只是简单地将onEvent开头的方法给封装到一个集合里面去了。
接着看注册里面,获取到以onEvent开头的方法后,将该method集合添加到一个mSubscriberMap中,该map中的key就是onEvent开头的方法的第一个参数,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];  
   }
}

该类有三个成员变量,可能现在有人不知道为啥要这么定义,到了后面用到的时候就知道为啥这么定义了。
好了,整个注册的过程就这样,最终的目的就是得到一个map对象。
下面来看看发送的过程吧:
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 {           
              /**           
               * 第二个参数是方法的参数,第-个参数是该类的对象                 
               */                
              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方法来接收处理消息了,这个地方就是核心的地方了。这里实际上bus类的post方法的参数就是这里的bus类中mSubscriberMap的key了,通过该key可以获取到mSubscriberMap中的value值了,也就是Subscriber集合了,现在知道Subscriber类的定义了吧,mMethod是方法名,mSubscriber是该类对象,实际上它的第三个成员变量没用到。最后通过反射来调用onEvent开头的方法,整个过程就这么简单,是不是现在一目了然了呢。
最后就是注销了:

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中的对象给至空了。
好了,整个过程就这样了,是不是几个过程都清楚了。

下面用一个demo来测试该事例吧:

demo.gif

整个的内容就这么多了,完全是靠自己的理解。如果有什么说得不清楚的地方,还需大家指出来。

借鉴的项目:https://github.com/avenwu/support

关于我:

email:a1002326270@163.com
github:enter

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 项目到了一定阶段会出现一种甜蜜的负担:业务的不断发展与人员的流动性越来越大,代码维护与测试回归流程越来越繁琐。这个...
    fdacc6a1e764阅读 3,161评论 0 6
  • 我每周会写一篇源代码分析的文章,以后也可能会有其他主题.如果你喜欢我写的文章的话,欢迎关注我的新浪微博@达达达达s...
    SkyKai阅读 24,900评论 23 184
  • 对于Android开发老司机来说肯定不会陌生,它是一个基于观察者模式的事件发布/订阅框架,开发者可以通过极少的代码...
    飞扬小米阅读 1,467评论 0 50
  • 有一个同学和我说了一件事,觉得可以作为日记素材,就写出来了。 一个客户的房子需要装修,他得到了两个报价,熟人报价是...
    安梓阅读 466评论 0 1