事件总线框架EventBus,该升级啦!

  • 作者:彭老师
  • 日期:2019-07-25
  • 类型:Android
  • 说明:本文源于彭老师手写摘要,如需转载请带上链接或注明出处!

EventBus(最新版3.1.1)问题和修复:

  • 1、发布粘性事件:触发了所有同类型订阅方法(粘性和非粘性),已修复
  • 2、粘性事件订阅方法无法第2次消费(很难满足复杂项目要求),已修复
  • 3、多次调用和移除粘性事件时,post会执行多次粘性事件订阅方法(非粘性正常),已修复
  • 4、优化索引方法,让api更简单直接
  • 5、重写注解处理器,方式:apt + javapoet(官方是传统写法)
  • 6、弱化了线程池,使用缓存线程池替代
  • 7、去除了对象池概念,考虑recycle问题。暂未测试内存泄漏情况
  • 8、修复Subscription对象匹配bug,删除hashCode无用方法
  • 9、纯反射技术完全剥离,第二个项目有完整详细介绍

EventBus开源地址:https://github.com/greenrobot/EventBus


Github的示例文档如下:

Add EventBus to your project

implementation 'org.greenrobot:eventbus:3.1.1'

EventBus in 3 steps

1、Define events:

public static class MessageEvent { /* Additional fields if needed */ }

2、Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};

Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle:

@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}

@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}

3、Post events:

EventBus.getDefault().post(new MessageEvent());

很遗憾告诉大家:这是错误的!

官方文档如出一辙(还是错误的):http://greenrobot.org/eventbus/documentation/how-to-get-started/

正确的写法到底是什么样呢?

1、是否添加了注解处理器

implementation 'org.greenrobot:eventbus:3.1.1'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'

2、是否创建了订阅索引

public class BaseApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
}
}

问题分析:

1、发布粘性事件:触发了所有同类型订阅方法(粘性和非粘性)

// 订阅粘性事件
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onMessageEvent(UserInfo user) {
Log.e("netease >>> ", user.toString());
}
// 发送粘性事件
EventBus.getDefault().postSticky(new UserInfo("simon", 35));
// 参考源码EventBus.java - 306行
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// 原因在这里
post(event);
}

2、粘性事件订阅方法无法第2次消费(很难满足复杂项目要求)

// 参考源码EventBus.java - 157行
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
}

3、多次调用和移除粘性事件时,post会执行多次粘性事件订阅方法(非粘性正常)

// 创建普通订阅方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(UserInfo user) {
Log.e("netease >>> ", "onMessageEvent");
}
// 创建粘性订阅方法
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onMessageEvent(UserInfo user) {
Log.e("netease >>> ", user.toString());
}
// Bug重现第1步
EventBus.getDefault().postSticky(new UserInfo("simon", 35));
// Bug重现第2步
EventBus.getDefault().register(this);
EventBus.getDefault().removeStickyEvent(UserInfo.class);
// Bug重现第3步
EventBus.getDefault().post(new UserInfo("simon", 35));

上述3步骤循环2次操作就会发现问题


4、优化索引方法,让api更简单直接

EventBus.getDefault().addIndex(new EventBusIndex());

更多技术内幕请关注:网易云课堂 - 微专业 - 安卓高级开发工程师