背景

最近项目做组件化,需要进行组件化的通信,有时候可能会出现异步的情况,事件接收方还没准备好事件就已经发送过来了。这时候想到了EventBus的粘性事件。什么是粘性事件呢,通俗点讲就是不达目的不罢休的事件,事件保证能发送到订阅者手里。

发送粘性事件

EventBus发送粘性事件非常简单,一段代码就可以搞定:

EventBus.getDefault().postSticky(event)

接收粘性事件

接收粘性事件也非常简单,注册方法上加个sticky = true即可

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)

public void loginSuccessEvent(event: LoginSuccessEvent){}

粘性事件代码解析

一行代码就能实现这件神奇的事情,那么中间到底发生了什么呢,下面我们分析下源码:

public void postSticky(Object event) {

synchronized (stickyEvents) {

stickyEvents.put(event.getClass(), event);

}

// Should be posted after it is putted, in case the subscriber wants to remove immediately

post(event);

}

从代码中发现首先会把粘性事件用stickyEvents缓存起来,然后像普通事件一样post出去。

stickyEvents是一个Map集合,加入这个集合里面会发生什么呢?

private final Map, Object> stickyEvents;

通过跟踪我们会发现以下代码

public void register(Object subscriber) {

Class> subscriberClass = subscriber.getClass();

List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

synchronized (this) {

for (SubscriberMethod subscriberMethod : subscriberMethods) {

subscribe(subscriber, subscriberMethod);

}

}

}

// Must be called in synchronized block

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

....省略N段代码...

if (subscriberMethod.sticky) {

if (eventInheritance) {

// Existing sticky events of all subclasses of eventType have to be considered.

// Note: Iterating over all events may be inefficient with lots of sticky events,

// thus data structure should be changed to allow a more efficient lookup

// (e.g. an additional map storing sub classes of super classes: Class -> List).

Set, Object>> entries = stickyEvents.entrySet();

for (Map.Entry, 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);

}

}

}

从上面可以看出在register事件的时候回调用subscribe方法,在subscribe中会处理stickyEvents中的粘性事件通过checkPostStickyEventToSubscription方法发送出去,继续跟踪发现最终都会走到下面这个方法里面

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);

}

}

subscription.subscriberMethod.method.invoke(subscription.subscriber, event)就是执行在订阅者那边定义的处理事件的方法,至此整个流程就结束了。

看到这里想必大家都发现了,粘性事件有可能会收到两次,注意我这里用的是有可能。

让我们分析以下两种场景:

第一种订阅者Activity已经启动了,这时候事件通过postSticky之后调用post发送,而stickyEvents中缓存的事件不会发送,这是为什么呢。前面分析stickyEvents中事件的处理是在事件register的时候,而这时候粘性事件还没有发送所以只会发送一次。

第二种订阅者Activity还没启动但是粘性事件发送了,这时候通过post方式发送的消息是收不到的,然后当订阅者Activity中register事件时就会再发送一遍粘性事件。

综述,最终事件只会发送一遍。

android 粘性弹窗,android组件化通信之EventBus粘性事件解析相关推荐

  1. vue组件化通信之兄弟组件传值

    vue组件化通信之父向子传值 vue组件化通信之子向父传值 在vue中兄弟节点传值一般有两种方法:$parent和 $root, 建议使用前者 使用$parent **parent.vue** < ...

  2. vue组件化通信之子向父传值

    vue组件化通信之子向父传值 vue组件化通信之兄弟组件传值 vue中子向父传递消息一般使用$emit,方法比较简单,直接看代码 父组件 <template><div>< ...

  3. vue组件化通信之父向子传值

    vue组件化通信之子向父传值 vue组件化通信之兄弟组件传值 父向子组件传值 常用的方法主要有三种:props.$refs.$children 建议使用前两种 使用props进行传值 parent.v ...

  4. Vue 组件化通信 provide inject ,dispatch ,boardcast

    入门 作为前端最容易上手的框架,Vue入门其实没啥说的,我放一段清单的代码,大家能看懂就说明能上手了 <template><div id="app">< ...

  5. Android热更新,android组件化通信

    2.集成SDK gradle这个配置 在app module的"build.gradle"文件中添加(示例配置): android { defaultConfig { ndk { ...

  6. Android 基于注解IOC组件化/模块化的架构实践

    当前参与的项目历史也很久远,第一行代码据说是写于2014年的某一天,那时Android用的ide还是Eclipse.那时Android还没有很好的架构指导(mvp.mvvm).那时Android最新的 ...

  7. android 电商app组件化,APICloud AVM多端开发案例深度解析(一)--生鲜电商app开发

    AVM多端开发是APICloud定义的一套新的代码编写标准(DSL):基于标准Web Components组件化思想,兼容Vue / React语法特性,通过一次编码,分别编译为Android和iOS ...

  8. Android:项目模块化/组件化的架构之路(一)

    文章目录 前言 推荐 模块化需要做什么 一.如何拆分项目 二.模块之间的通信 1. 常用的通信方式 2. 改善通信方式 2.1 使用接口进行通信 2.2 如何对外暴露接口 2.3 使用EventBus ...

  9. android注册弹窗,Android开发之PopupWindow创建弹窗、对话框的方法详解

    本文实例讲述了Android开发之PopupWindow创建弹窗.对话框的方法.分享给大家供大家参考,具体如下: 简介: PopupWindow 可创建类似对话框风格的窗口 效果: 使用方法: 使用P ...

最新文章

  1. Linux服务器---安装tftp-server
  2. 双系统gazebo闪退_记录Ubuntu16.04下PX4联合Gazebo仿真时遇到的问题与解决方法
  3. Oracle可以处理LOB字段的常用字符函数
  4. python计算每月工资-[Python] 2018新税法下工资计算
  5. 大数据WEB阶段Spring框架(四)Spring-MVC
  6. 【转】x.509证书在WCF中的应用(CS篇)
  7. Java设计模式笔记(6)观察者模式
  8. vmware挂载san存储_细述企业级存储NAS和SAN差异
  9. linux中进程的用户管理
  10. SQL2005存储过程解密
  11. Python单例模式的4种实现方法(转)
  12. Netty工作笔记0031---NIO零拷贝应用案例
  13. 二级mysql与access数据库_2017计算机二级Access数据库基础教程
  14. 01 分布式系统架构的冰与火
  15. Ftp搜索引擎开发实践
  16. linux 筛选重复数据,Linux下uniq筛选
  17. keep行走和计步_KEEP跑步计步器
  18. 股票自动交易接口简化
  19. maven安装及环境部署(IDEA)
  20. 2021.11.25 小组加分制度的破绽

热门文章

  1. 计算机二级python 公共基础题总结
  2. 2106 Problem F Shuffling Along
  3. MICK-SQL基础教程(第二版)第七章 集合运算
  4. 微信支付 回调地址哪里设置
  5. tomcat项目部署到本地局域网访问
  6. 2018世界机器人大会来了
  7. java数据结构YZP专栏-----链表
  8. Linux搭建MonggoDB环境
  9. 梦幻诛仙 修改服务器时间,《梦幻诛仙手游》2019年3月12日14:00~19:00数据互通公告...
  10. url 转义 java_Java 特殊字符URL转义 | 学步园