内容简介:EventBus消息支持通过不同线程模式发送,以此满足注册类必须包含至少一个接收事件的方法Subscribe接口为修饰接收者的注解,
一、简介
EventBus消息支持通过不同线程模式发送,以此满足 Android 不同应用场景的需求。通过订阅者内的订阅方法可知,线程模式是通过注解参数进行配置
二、用法
注册类必须包含至少一个接收事件的方法
@Subscribe(threadMode = ThreadMode.MAIN, sticky = false, priority = 0) fun onEventReceived(event: UserEvent) { val name = event.name val age = event.age Log.i(TAG, "Event received, Name: $name, Age: $age.") }
三、类介绍
Subscribe接口为修饰接收者的注解, threadMode() 决定订阅者方法触发时所在的线程。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { ThreadMode threadMode() default ThreadMode.POSTING; .... .... }
EventBus支持的线程模式都保存在枚举类中。每个订阅者方法默认都定义一种线程模式,该模式告诉 EventBus 通过哪种线程去调用订阅者方法。
public enum ThreadMode
四、线程模式
ThreadMode枚举类中默认包含5种线程模式:
4.1 POSTING
订阅者在发布线程相同的线程上被调用,本模式是 EventBus 默认线程模式。因为完全避免线程切换,此线程模式的事件分发意味着能减少性能开销。
因此,对已知能在短时间内、主线程上完成的单个任务,本模式是首要推荐的。就是说此模式处理事件时,方法需要迅速执行完毕,并返回方法避免阻塞(主线程)发布线程。
POSTING,
4.2 MAIN
如果 EventBus 正在 Android 中使用,订阅者会在主线程中进行调用。如果消息发布线程就是主线程,则订阅者方法直接调用,并阻塞发布线程。否则,事件在消息队列等待主线程(非阻塞性的)分派。
由于接收者方法执行在主线程上,所以方法逻辑应轻巧,或在内部开启子线程执行重量级操作,以此避免阻塞主线程运行。推理可知,如果订阅者方法后续还有更多事件需要在主线程上发出,那么这些事件也会受到该次阻塞的影响。
如果 EventBus 所在环境不是 Android ,则本模式的执行行为和 POSTING 模式相同。
MAIN,
4.3 MAIN_ORDERED
在 Android 中订阅者方法也是在主线程中被调用。但和 MAIN 模式不同的,是本模式的消息会直接进入属于主线程的消息队列中排队等待执行,而不是阻塞主线程直接运行。
MAIN_ORDERED,
4.4 BACKGROUND
在 Android 中,此模式的订阅者会在后台线程调用。如果发布消息的线程不是主线程,则订阅者方法直接在发布线程上调用。如果消息发布线程是主线程, EventBus 会使用单个后台线程,该线程会顺序分派所有事件。如果订阅者使用此种模式,就应该快速从方法中返回,避免阻塞这个单一后台线程的运行。在非 Android 直接使用一个后台线程,不区分主线程。
BACKGROUND,
4.5 ASYNC
订阅者会在分离的线程上调用。此线程独立于事件发布线程和主线程。使用这种模式时,发送事件不会等待订阅者方法。可使用这个模式处理订阅者方法的耗时事件,例如:进行网络访问。为了避免同时触发大量、长期运行的订阅者方法, EventBus 使用了线程池,从已完成的异步订阅者通知复用线程。
ASYNC
实现
前文提到实现方法 EventBus.postToSubscription() 的逻辑就不难理解了。
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 { // 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: asyncPoster.enqueue(subscription, event); break; // 传入未知threadMode,引起异常 default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
invokeSubscriber直接在消息发送者所在线程上调用目标方法。
void invokeSubscriber(Subscription subscription, Object event) { try { // subscription.subscriber:通过实例调用方法 // event:调用时传递给方法的参数 subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { // 捕获订阅者方法运行时异常,避免导致EventBus崩溃 handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 【重回基础】线程池源码剖析:Worker工作线程
- 线程池的使用和源码剖析
- Java线程池ThreadPoolExecutor实现原理剖析
- Java 多线程并发读写锁 ReadWriteLock 实现原理剖析
- MySQL(InnoDB剖析):05---InnoDB体系架构(后台线程、内存池、文件)
- 【Java集合源码剖析】ArrayList源码剖析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
鳥哥的Linux私房菜(第四版)
鳥哥 / 碁峰資訊股份有限公司 / 2016-1-25 / TWD 980.00
本書前三版均蟬聯電腦專業書籍Linux暢銷排行榜Top1,為地表最暢銷的Linux中文書籍! 您是有意學習Linux的小菜鳥,卻不知如何下手?您是遨遊Linux的老鳥,想要一本資料豐富的工具書?本書絕對是最佳選擇! ※鳥哥傾囊相授,內容由淺入深 書中包含了鳥哥從完全不懂Linux到現在的所有歷程,鳥哥將這幾年來的所知所學傾囊相授,以最淺顯易懂的文字帶領您進入Linux的世界。 ......一起来看看 《鳥哥的Linux私房菜(第四版)》 这本书的介绍吧!