EventBus使用详解

2016-10-01  本文已影响2533人  Simon_z

本文的EventBus,是指greenrobot的 EventBus, 主要以EventBus3.0 讲解;

什么是EventBus?

EventBus事件总线, 用于简化Android程序内,各个组件,线程之间的事件传递; 订阅发布模式,将事件的接收者和发布者解耦,一旦publisher发出消息,subscribe自己按需改变; 我个人喜欢把它拿来和BroadCast比较;

在什么场景下使用

  1. 复杂逻辑下的对象传递
  2. 函数的调用者与被调用者需要低耦合,或者框架设计之初,无法预料到的调用

eg. 上面的使用场景,在我们代码中时长出现的场景就是,监听器的传递,回调函数和各种Listener;
比如,在一个activity中,又2个fragment,而每个fragment中又各嵌套一个子fragment, 其中一个子fragment要监听另一个子fragment中的按钮变化; 一般做法是将listener作为函数参数传递, 或者设置为静态变量;
第二个, 就和BoardCast相似

怎么使用

  1. 在gradle中添加依赖
dependencies {
       compile 'org.greenrobot:eventbus:3.0.0'
}
  1. 注册和取消注册
    在要接收消息的类中register unregister, 和广播的注册类似, 一般在activity的 onCreate 和 onDestory 方法中进行
EventBus.getDefault().register( this );
EventBus.getDefault().unregister( this );
  1. 申明处理消息的函数;
    在接收消息的函数上,加上@Subscribe, EventBus是按函数参数的类型确认消息的接收者的, 此函数只能有且仅有一个参数;
@Subscribe(threadMode = ThreadMode.MAIN, priority = 1, sticky = false)
public void onEvent( TestEvent  testEvent ){    
    Log.e( "zy", ">>>> receiverEvent");
}

只需要在函数上加上 @Subscribe 注解即可, 此注解还可以带上额外的参数

  1. 发送消息
    所谓的消息,就只是一个java对象, 发送消息就是把这个对象,传递给处理消息的函数; EventBus消息和EventBus的对象实例有关, 用一个EventBus对象发送的消息,必须是用同一个EventBus对象注册的才能收到消息.
// 发送黏性消息
EventBus.getDefault().postSticky( new TestEvent() );
// 发送普通的消息
EventBus.getDefault().post( new TestEvent() );

发送的消息有2种,
sticky黏性消息, 当消息发送出去之后,如果没有消息接收者处理这个消息,此消息会暂时存储在eventBus实例中, 当后面注册接受者时,如果合适的处理者, 将会把消息给处理者去处理;我个人喜欢用这个来做数据的预加载;

  1. 提升性能, 增加编译时注解处理
    由于android机器本身性能有限,一般不建议使用运行时注解,EventBus的注解声明为Runtime, 但它同时支持编译时注解和运行时注解, 当没配置编译时注解处理器时, 会自动通过反射查找运行时的注解;
    1. 添加注解处理器依赖
buildscript {
    ...
    dependencies {
          classpath 'com.android.tools.build:gradle:2.1.0'
          // 在最外层添加gradle的插件依赖
          classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
      }
  ...
}
// 项目中 增加注解处理器插件
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
       compile 'org.greenrobot:eventbus:3.0.0'
      // 添加注解处理器
      apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
apt {
    arguments {
        // 注解处理器 最终生成的java文件位置
        eventBusIndex "com.zy.test.MyEventBusIndex"
    }
}
2. 初始化EventBus时, 使用注解处理器生成的类文件
    ```java  
mEventBus = EventBus.builder().addIndex( new MyEventBusIndex() ).build();
     ```
 EventBus的消息和EventBus实例有关系, 自己配置的EventBus实例,一般需要用单例保存, 确保发送和接收消息的地方,使用的是同一个实例

关于其他的一些细节

- 消息处理者的继承
EventBus的消息处理者,是可以继承的, 父类中的消息处理器, 在子类中仍可使用; 这是一个比较好的功能, 比如通用的消息接收处理,我们在BaseActivity中声明一次, 子类都可以使用了; 此功能可以关闭, 在构建Eventbus实例时, 调用 `EventBus.builder().eventInheritance( false )` ; 官方的说法是关闭后可以提供20%的性能;

对比

  1. Boardcast
    优点: 可以指定运行线程, 消息处理可继承, 代码简单, 消息处理可继承, 低延迟, 对消息数据无要求(不需要实现Parcelable或者Serializable接口)
    缺点: 无法跨进程
  2. LocalBroadcastManager
    这个除了广播的低延迟外, Boardcast的缺点都有, 并且它还不能不能跨进程, 没有黏性广播
  3. RxBus

源码初探

EventBus的源码不多, 这里只讲一下大概, 具体细节大家自己去读源码
源码版本( 66ead83 )

  1. EventBus.java
    此类对外提供所有的接口,register, unregister, post;
    提供一个默认的单例对象, 通过getDefault()获取;
    核心的变量如下
/** eventType和消息接收者存储的map, key是event的class, value是接收者的信息, Subscription中包含的接收消息的对象, 处理消息的方法 */
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
/** 消息处理者和其所包含的能处理的event的Map, key为消息处理者的实例, value为其所能处理的event的类型 */
private final Map<Object, List<Class<?>>> typesBySubscriber;
/** sticky event 的存储的Map, key为event的class, value是具体事件的对象, 每种类型的sticky event 最多存储一个 */
private final Map<Class<?>, Object> stickyEvents;
  1. SubscriberMethodFinder.java
    用于寻找消息处理者的方法, 里面有一个静态变量 Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE 用于保存找到的消息处理这, 加快下一次查找过程

  2. HandlerPoster.java
    HandlerPoster 本质是一个Handler, 使用主线程的Looper, 可以看一下初始化语句 mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); 发送到主线程的消息, 实质都是用此发送一个Message, 然后在Handler#handleMessage中, 调用 Method#invoke(Object, Event);

  3. AsyncPoster.java BackgroundPoster.java
    名称已经很明显, 处理后台消息的2个类; 本质都是Runnable, 都从消息队列中获取消息, 然后在线程池中执行

  4. PendingPostQueue.java
    消息存储的地方, 一个简单的链表结构

上一篇 下一篇

猜你喜欢

热点阅读