- 示例使用
- 时序图
- 源码解读
EventBus 使用
- 官网定义:
EventBus
是一个使用 Java 写的观察者模式,解耦的Android开源库。EventBus 只需要几行代码即可解耦简化代码,加快开发速度。使用:
- 定义 events
Events 就是个 POJO 类
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
- 准备 subscribers
需要
```java
// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
doSomethingWith(event);
}
```
subscribers 需要注册
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
- 发送 evnets
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
在需要接收时间的地方,通过 @Subscribe
写
Github:https://github.com/greenrobot/EventBus
官网:http://greenrobot.org/eventbus/
时序图
源码解析
- 思路:通过 EventBus.gerDefault().register(this),把当前的 Activity 或者 Fragment 和通过反射拿到在其中用 @Subscribe 修饰的方法保存到相关的容器中,通过 post() 方法携带 Event ,从容器中取出相关的 subscribe 和方法,通过反射调用该方法,把消息分发到目标 subscribe 。在 Activity 或 Fragment 生命周期销毁的时候,通过 unRegister() 把 subscribe 从容器中移除,去掉订阅者模式,防止内存泄漏。
- 相关类
- interface Poster:接口,唯一方法 enqueue(), 加入队列的。
- HandlerPoster: 切换到 UI 线程的 Poster 实现类,内部通过一个链表存储消息,通过 Handler 把消息切换到 UI 线程,从而实现更新 UI 线程
- BackgroundPoster: 后台执行 Event 的 Poster 实现类
- AsyncPoster:与 BackgroudPoster 类似
- PendingPostQueue: 存储 PendingPost 的链表
- Subscription: 订阅对象,有 subscriber 和 subscribeMethod 构成
- SubscriberMethod: subscriber 中的接收方法,有 方法名称 ,threadMode, priority, 是否是粘性, eventType
- PostingThreadState:保存在 ThreadLocal 中,主要存储 event 的相关信息, 是否在主线程,订阅者信息,是否取消,是否已发送。
- MainThreadSupport: 切换到 UI 线程用的,配合 HandlerPoster 一起使用。
- SubscriberInfo:Base class for generated index classes created by annotation processing
- 从使用的入口开始
注册:EventBus.getDefault().register(this)
发送消息:EventBus.getDefault().post(event)
- 发送消息一般调用 post() 方法,然后把定义的 Event 发送出去,看下 post() 方法源码
public void post(Object event) { // ThreadLocal 中获取变量 postingState. PostingThreadState postingState = currentPostingThreadState.get(); // 从 postingState 中拿到 ArrayList List<Object> eventQueue = postingState.eventQueue; // 把当前 event 加入到 ArrayList 中 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 { // ArrayList 不为 Null , 循环取出来数据,通过 postSingleEvent() 发送。 while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { // Arraylist 中所有的消息都发送完成,设置 isPosting 和 isMainThread 为 false。 postingState.isPosting = false; postingState.isMainThread = false; } } }
从 ThreadLocal 中拿到 PostingThreadState ,然后把消息放入的到变量 ArrayList 中,然后判断 postingState 的状态,是否处于发送状态,不在发送状态的话,进入条件判断然后遍历 ArrayList 调用 postSingleEvent() 方法把 event 发送。看下 postSingleEvent() 源码
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); // 订阅者信息是否能找到 boolean subscriptionFound = false; // 通过 EventBusBilder 传入的, 默认为 true if (eventInheritance) { List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); // 进入到了 postSingleEventForEventType() 方法 subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } if (!subscriptionFound) { if (logNoSubscriberMessages) { logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }
在方法 postSingleEvent() 中,通过成员变量 eventInheritance (表示是否要向上查找事件的父类) 来判断,默认为 true ,所以进入 if 中,lookupAllEventTypes() 方法会通过递归的方式进行查找所有父类事件并存到 List 中。然后通过遍历调用 postSingleEventForEventType() 方法进行处理
看下 lookupAllEventTypes() 源码,其中 addInterfaces() 通过递归拿到全部的父类事件。
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); addInterfaces(eventTypes, clazz.getInterfaces()); clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; } }
addInterfaces()
源码,通过递归调用方法,查找所有的父类事件并加入到 List 中static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) { for (Class<?> interfaceClass : interfaces) { if (!eventTypes.contains(interfaceClass)) { eventTypes.add(interfaceClass); addInterfaces(eventTypes, interfaceClass.getInterfaces()); } } }
看下
postSingleEventForEventType()
源码。成员变量subscriptionsByEventType
是一个Map<Class<?>, CopyOnWriteArrayList<Subscription>>
, 通过成员变量拿到 subscriptions ,然后遍历该列表,调用 postToSubscription() 方法private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { // 线程安全的ArrayList 保存订阅者信息 CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { // 根据 clz 获取该类的订阅者信息列表 subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { //遍历订阅者信息列表 for (Subscription subscription : subscriptions) { //设置 postingState 的状态 postingState.event = event; postingState.subscription = subscription; // 是否可以取消,默认不可取消 boolean aborted = false; try { // 传入订阅者信息,event, 是否在主线程 postToSubscription(subscription, event, postingState.isMainThread); // postingState.canceled 默认是 false 。表示不可取消 aborted = postingState.canceled; } finally { //postingState 恢复成默认状态。 postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if (aborted) { break; } } return true; } return false; }
进入
postToSubscription()
源码,根据订阅者在注册的时候存入的threadMode
把event
分发到不同的线程中。根据threadMode
不同,可以分为POSTING
,MAIN
,MAIN_ORDERED
,BACKGROUND
,ASYNC
。 变量 mainThreadPoster 其实是 HandlerPoster ,把消息发送到 UI 线程的。private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case POSTING:// 订阅者与 event 在相同线程 invokeSubscriber(subscription, event); break; case MAIN:// UI 线程 // event 是在 UI 线程,则直接通过反射调用。 if (isMainThread) { invokeSubscriber(subscription, event); } else { // event 不在 UI 线程,则加入队列,通过 Handler 切换到 UI 线程 mainThreadPoster.enqueue(subscription, event); } break; case MAIN_ORDERED://UI线程,按照顺序发送消息 if (mainThreadPoster != null) { mainThreadPoster.enqueue(subscription, event); } else { // temporary: technically not correct as poster not decoupled from subscriber invokeSubscriber(subscription, event); } break; case BACKGROUND:// if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; case ASYNC://订阅者单独一个线程,不同于发送线程和UI线程。 asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
invokeSubscriber() 方法,通过反射执行订阅者的订阅方法
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); } }
反注册:EventBus.getDefault().unregister(this);
原文地址:https://www.cnblogs.com/liyiran/p/9172989.html