EventBus的详细解析

项目使用的技术呢,说白了,就是将要传递的event(一个Object对象,可任意自定义),发送到公共的组件EventBus中进行存储,

在通过EventBus传递给订阅者(使用者),订阅者收到event消息,就可以自行处理了。


不要被标题迷惑了,其实在任何地方 都可以发送和接收event(event,是一个通称,表示任意的数据对象,是一个消息类型)。

当然有需要注意的地方了,往下看吧。


分析一个基本的使用流程:


1. 自定义一个event类型:需要什么样的数据,就定义成什么样,随意了


2. 确定在哪里来接收该event,就在哪里调用EventBus.getDefault().register()进行订阅者的注册。

  EventBus 一看就是个单例类,所以通过它存储、发送event。

     可以在要处理事件的地方注册和接收;在发送事件的地方直接调用post(event)

   register()有多个重载方法:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public void register(Object subscriber) {  
  2.     register(subscriber, false0);  
  3. }  
  4.   
  5. public void register(Object subscriber, int priority) {  
  6.     register(subscriber, false, priority);  
  7. }  
  8.   
  9. public void registerSticky(Object subscriber) {  
  10.     register(subscriber, true0);  
  11. }  
  12.   
  13. public void registerSticky(Object subscriber, int priority) {  
  14.     register(subscriber, true, priority);  
  15. }  
  16. private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {  
  17.     ...  
  18. }  

      看名字也很好理解,subscriber即订阅者(接收处理event的类);priority即优先级,表示优先处理;

      sticky粘性的意思,在源码中会有一个map对象,来存储sticky的event,

          因为map的key是onEvent...()方法的第一个参数类型,

          一般呢,这第一个参数就是订阅者对象,所以map会存储该类型的最后一次发送的event对象。

      这些register都会最终调用一个私有register方法实现的,在这个方法里有个参数是SubscriberMethod对象。

            调用subscriberMethod.findSubscriberMethods(), 查找到订阅者定义的接收处理event的方法,

      并在EventBus中存起来。


3.  在订阅者中定义接收处理event的方法,约定为:

     onEvent、onEventMainThread、onEventBackgroundThread、onEventAsync 

     使用时类似这样的:public void onEvent(Object event)。 onEvent对应PostThread,其他各自对应ThreadMode中的其他定义。

     onEvent后面跟的这些名称的意义,见ThreadMode


4. 发送事件

   调用EventBus.getDefault().post(Object event),发送事件   

   源码中会调用postToSubscription(),发送event给对应的订阅者方法


ThreadMode

   这是一个枚举类。定义了四种类型:PostThread、MainThread、BackgroundThread、Async 

   PostThread  事件event的处理和发送都在相同线程中

   MainThread  事件event的处理在主线程中,小心ANR

   BackgroundThread 事件event的处理在后台线程(非主线程)中,它是阻塞式的,如有多个事件发送过来,会一个一个处理

   Async 事件event的处理是异步的,即新开一个线程进行处理。

   对应的接收事件方法:

   PostThread ---- onEvent() 在发送事件的线程中接收事件

   MainThread ---- onEventMainThread() 在主线程中接收

   BackgroundThread ---- onEventBackgroundThread 在后台线程中接收

   Async ---- onEventAsync 在异步线程中接收


例:在activity2中post(event),在activity1中注册为订阅者 并 接收事件 onEvent。 要在哪种类型线程中接收 ,参考上面的说明

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public class EventBusActivity1 extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.   
  7.         EventBus.getDefault().register(this); //注册接收器  
  8.     }  
  9.   
  10.     //两个activity中使用eventBus  
  11.     public void eventBusEventWith2Acti(View view) {//onClick方法  
  12.         startActivity(new Intent(this, EventBusActivity2.class));  
  13.     }  
  14.   
  15.     @Override  
  16.     protected void onDestroy() {  
  17.         super.onDestroy();  
  18.   
  19.         EventBus.getDefault().unregister(this);   
  20.     }  
  21.   
  22.     public void onEvent(Object event) { //接收方法  在发关事件的线程接收  
  23.         Looper.prepare();  
  24.         Toast.makeText(this"recevie a event:" + event + Thread.currentThread().getName(), Toast.LENGTH_SHORT).show();  
  25.         Looper.loop();  
  26.     }  
  27.   
  28. }  
  29.   
  30. public class EventBusActivity2 extends Activity {  
  31.   
  32.     @Override  
  33.     protected void onCreate(Bundle savedInstanceState) {  
  34.         super.onCreate(savedInstanceState);  
  35.   
  36.         new Thread() {  
  37.             @Override  
  38.             public void run() {  
  39.                 EventBus.getDefault().post(this.getClass().getSimpleName() + " 发了一个消息");  
  40.             }  
  41.         }.start();  
  42.         finish();  
  43.     }  
  44. }  


使用注意:

  1. 在register(Object subscription) 注册的subscription对象中 定义onEvent... 方法,至少需要定义一种

  2. 如果所有的onEvent... 方法都注册 那么 都将收到消息(内部机制就是反射判断有哪些方法,从消息队列中取event)

  3. onEvent(event) 所接收到的消息的数据类型任意(随你的意),在任意位置使用post(event)发送事件

  4. 实际使用时,异步操作选用onEventAsync,主界面操作选用onEventMainThread

  5. 在代码混淆时,注意保留onEvent... 方法


----------------------------------------------------------------------------------------------------分隔线-----------------------------------------------------------------------------------

实际工作中,我把该组件用于,跨activity、fragment等通知,即只要不是在同一个class文件中,需要通知交互的地方,就可以使用它

使用流程

> 定义一个事件类, class EventBean;在里面定义每种通知事件的常量类型。这样对于不需要传参的通知是够用了

> 在EventBean中,定义一个属性:Object data; 用于存储任意参数类型

> 如果当前在A-Fragment中,需要传一个 List<User> users;  给MainActivity,对users排序

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * @Description: 管理所有跨界面消息通知事件 
  3.  * @author aa86799@163.com 
  4.  */  
  5. public class EventBean {  
  6.   
  7.     private int mEvent;  
  8.     private Object mData;  
  9.       
  10.     /**主界面 对User 集合排序*/  
  11.     public static final int EVENT_MAINACTIVITY_SORT_USER = 1;  
  12.   
  13.   
  14.     public EventBean() {  
  15.   
  16.     }  
  17.       
  18.     public EventBean(int event) {  
  19.         this.mEvent = event;  
  20.     }  
  21.   
  22.     public EventBean(int event, Object data) {  
  23.         this(event);  
  24.         this.mData = data;  
  25.     }  
  26.   
  27.     public int getEvent() {  
  28.         return this.mEvent;  
  29.     }  
  30.   
  31.     public void setEvent(int event) {  
  32.         this.mEvent = event;  
  33.     }  
  34.   
  35.     public Object getData() {  
  36.         return mData;  
  37.     }  
  38.   
  39.     public void setData(Object data) {  
  40.         this.mData = data;  
  41.     }  
  42.       
  43.       
  44. }  

在fragment中,发消息通知时大概是这样的:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. EventBus.getDefault().post(new EventBean(EventBean.EVENT_MAINACTIVITY_SORT_USER,  users));  

在MainActivity中

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public void onEventMainThread(EventBean event) { //在主线程中接收    
  3.     switch (event.getEvent()) {  
  4.     case EventBean.Event_SORT_USERS:  
  5.         LogUtil.i(TAG, "用户排序");  
  6.                 List<user> users = (List<user>)event.getData();  
  7.         sortUsers(users);  
  8.         break;  
  9.     default:  
  10.         break;  
  11.     }  
  12. }  

—————————————————————2016-04-26——————————————————————

Android Studio 加载了EventBus的Library;发现已经升级到3.0了,用法有变化:

主要是订阅(接收)事件消息的方法上,需要一个注解,这个比较麻烦


订阅事件的方法随意命名(即不用像老版本一样,必须使用约定的方法名),只要在方法上加一个注解

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Documented  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Target({ElementType.METHOD})  
  4. public @interface Subscribe {  
  5.     ThreadMode threadMode() default ThreadMode.PostThread;  
  6.   
  7.       
  8.     boolean sticky() default false;  
  9.   
  10.       
  11.     int priority() default 0;  
  12. }  

使用如下:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Subscribe(threadMode = ThreadMode.MainThread, sticky = true, priority = 1)  
  2. public void onEvent(EventBean event){}  

注解中的属性,都有默认值的:

threadMode 表示在哪个线程中接收消息

sticky 如果为true,表示收到粘性事件;相应的在发送事件时,要使用postSticky(Object event);

priority 优先级,值越大,越先处理


关于sticky,EventBus类中源码:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky 
  3.  * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}. 
  4.  */  
  5. public void postSticky(Object event) {  
  6.     synchronized (stickyEvents) {  
  7.         stickyEvents.put(event.getClass(), event);  
  8.     }  
  9.     // Should be posted after it is putted, in case the subscriber wants to remove immediately  
  10.     post(event);  
  11. }  
  12.   
  13. /** 
  14.  * Gets the most recent sticky event for the given type. 
  15.  * 
  16.  * @see #postSticky(Object) 
  17.  */  
  18. public <T> T getStickyEvent(Class<T> eventType) {  
  19.     synchronized (stickyEvents) {  
  20.         return eventType.cast(stickyEvents.get(eventType));  
  21.     }  
  22. }  

源码中的stickyEvents是一个Map类型。由此可见,多次postSticky同一类型后,

由getStickyEvent(class),可以拿到最新的该类型对象


其它方法:

eventbus.removeAllStickyEvents(); //删除所有粘性事件
eventbus.cancelEventDelivery(Object event); //取消事件提供(发送)


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值