EventBus 是一款针对 Android 优化的发布/订阅事件总线
一、使用方法
1、EventBus 的三要素:
-
事件、任意类型对象
-
事件订阅者、任意
@Subscribe
注解方法 -
事件发布者、EventBus 对象,默认
EventBus.getDefault()
2、代码示例
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1、注册
EventBus.getDefault().register(this);
}
// 3、接收消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onSubscribeEvent(MessageEvent messageEvent) {
Log.i(TAG, "onSubscribeEvent: " + messageEvent.getMessage());
}
@Override
protected void onDestroy() {
// 4、注销
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
// 2、发送消息
EventBus.getDefault().post(new MessageEvent("hello wshunli"));
3、EventBus 的 ThreadMode(线程模型)
- POSTING、和发送同一线程
- MAIN、主线程
- MAIN_ORDERED、主线程顺序执行
- BACKGROUND、非主线程;如果主线程发出,在子线程执行,如果子线程发出,在相同线程执行
- ASYNC、无论从什么线程发出,总是在
新建
子线程执行
4、粘性事件(先发送,后注册接收)
EventBus.getDefault().postSticky(new MessageEvent("粘性事件"));
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onSubscribeStickyEvent(MessageEvent messageEvent) {
Log.i(TAG, "onSubscribeStickyEvent: " + messageEvent.getMessage());
}
implementation 'org.greenrobot:eventbus:3.2.0'
二、源码分析
2.1、EventBus 构造
public class EventBus {
static volatile EventBus defaultInstance;
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
// 默认实例,单例、双重校验锁
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
// 构造方法
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
// ***
}
}
EventBus 对象之间,订阅方法是隔离的,一般使用 getDefault()
即可。
2.2、注册订阅
// EventBus
private final SubscriberMethodFinder subscriberMethodFinder;
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
// (1)获取订阅方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// (2)订阅方法注册
subscribe(subscriber, subscriberMethod);
}
}
}
(1)查找订阅方法
// SubscriberMethodFinder
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
private List<SubscriberInfoIndex> subscriberInfoIndexes;
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 从缓存中获取,订阅方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// 是否忽略订阅信息索引
if (ignoreGeneratedIndex) {
// 通过反射
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 通过索引
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
Eventbus 支持 通过在编译期创建索引(SubscriberInfoIndex)以提高程序运行性能
https://greenrobot.org/eventbus/documentation/subscriber-index/
// 使用方法,编译时生成 MySubscriberInfoIndex 类
EventBus.builder().addIndex(new MySubscriberInfoIndex()).installDefaultEventBus();
// EventBusBuilder,添加索引信息
List<SubscriberInfoIndex> subscriberInfoIndexes;
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if (subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
// EventBus 构造时存入 SubscriberMethodFinder
EventBus(EventBusBuilder builder) {
//***
subscriberMethodFinder = new SubscriberMethodFinder(
builder.subscriberInfoIndexes,
builder.strictMethodVerification,
builder.ignoreGeneratedIndex);
//***
}
// SubscriberMethodFinder 获取订阅方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 从索引中中获取 SubscriberInfo
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 索引中没有,反射获取
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
private SubscriberInfo getSubscriberInfo(FindState findState) {
// ***
// 构造时传入 subscriberInfoIndexes 对象
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
反射方式比较简单,不再粘贴代码。
(2)订阅方法注册
// 事件 => Subscription 列表
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// 订阅者 => 事件列表
private final Map<Object, List<Class<?>>> typesBySubscriber;
// 存储粘性事件
private final Map<Class<?>, Object> stickyEvents;
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 事件,eventType 订阅方法参数类型
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 事件对应的 Subscription 列表
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
// ***
int size = subscriptions.size();
// 遍历,根据优先级插入
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// 存储订阅者及对应的事件列表
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 粘性事件处理
if (subscriberMethod.sticky) {
if (eventInheritance) {
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
2.3、事件的发送、处理
(1)普通事件
// EventBus
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
// PostingThreadState
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
// 发送普通事件
public void post(Object event) {
// 当前线程 发送状态
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
// 添加至事件队列
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
// 发送方法
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
// ***
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
// ***
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 获取事件对应的 subscriptions
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted;
try {
// 发送方法
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
// 当前线程处理
case POSTING:
invokeSubscriber(subscription, event);
break;
// 主线程处理
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
// Handler 发送消息
mainThreadPoster.enqueue(subscription, event);
}
break;
// 主线程顺序
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
// 子线程
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
// 在新建子线程
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
// 调用订阅方法
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
(2)粘性事件
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// 普通事件
post(event);
}
粘性事件仅将事件存入 stickyEvents 对象,真正调用在注册方法
// EventBus#subscribe
if (subscriberMethod.sticky) {
if (eventInheritance) {
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// 普通事件相同
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}
2.4、注销订阅
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
将订阅者、订阅方法从列表中移除
三、总结
优点,组件间通信解耦,预编译生成效率较高
缺点,代码可读性变差,逻辑分散
源码解析:
-
Android事件总线(一)EventBus3.0用法全解析 | BATcoder - 刘望舒:http://liuwangshu.cn/application/eventbus/1-eventbus.html
-
Android事件总线(二)EventBus3.0源码解析 | 刘望舒的博客:http://liuwangshu.cn/application/eventbus/2-eventbus-sourcecode.html
-
Android主流三方库源码分析(九、深入理解EventBus源码) | Deep into Android:链接
-
【Bugly干货分享】老司机教你 “飙” EventBus 3 - 腾讯bugly - 博客园:https://www.cnblogs.com/bugly/p/5475034.html
-
EventBus3.0 性能提升之添加索引_zhangke-CSDN博客:https://blog.csdn.net/kaifa1321/article/details/79761507
评论 (0)