又到周五啦,先祝大家周末愉快。

今天继续发车,本篇文章来自 谢三弟 的投稿,从官方文档以及源码入手,介绍了使用RxJava实现RxBus的原理。最后,想容易得看懂本文,前提是需要对RxJava有一定了解。

谢三弟 的博客地址:

http://imxie.cc

序言

很早之前有看过别人实现的 RxBus , 当初也只是随意用用而已,没有想过去研究。今天看到 brucezz 天哥在群里分享了一把,自己也加入了讨论,下来还实践了一把,所以想借此篇进入到源码层,深刻体验下 RxBus 这辆 “兰博基尼” 的设计美感和独特魅力。

RxBus

准备

推荐先看看 RxBus 的简单实现和用法,地址在这里:


RxBus的简单实现

http://brucezz.itscoder.com/articles/2016/06/02/a-simple-rxbus-implementation

解剖

让我们看看这辆车到底用了些什么?

  • Subject

  • SerializedSubject

  • PublishSubject

  • CompositeSubscription

从Subject开始发车

官方解释

这是 Subject 的中文解释:

Subject 可以看成是一个桥梁或者代理,在某些 ReactiveX 实现中(如 RxJava),它同时充当了 ObserverObservable 的角色。因为它是一个Observer,它可以订阅一个或多个 Observable;又因为它是一个Observable,它可以转发它收到(Observe)的数据,也可以发射新的数据。

由于一个 Subject 订阅一个 Observable,它可以触发这个 Observable 开始发射数据(如果那个Observable是”冷”的–就是说,它等待有订阅才开始发射数据)。因此有这样的效果,Subject 可以把原来那个”冷”的 Observable 变成”热”的。

Subject源码

源码:


Subject 只有两个方法:

hasObservers() 方法的解释是:

Indicates whether the {@link Subject} has {@link Observer Observers} subscribed to it.

判断 Subject 是否已经有 observers 订阅了 有则返回 true

toSerialized() 方法的解释是:

Wraps a {@link Subject} so that it is safe to call its various {@code on} methods from different threads.

包装 Subject 后让它可以安全的在不同线程中调用各种方法。

为什么调用这个方法后就可以是线程安全了呢?

我们看到 toSerialized() 返回了 SerializedSubject<T, R> 。我们先到这里打住,稍后我们再看看该类做了什么。

PublishSubject解释

RxJava 里有一个抽象类 Subject,既是 Observable 又是 Observer,可以把 Subject 理解成一个管道或者转发器,数据从一端输入,然后从另一端输出。

Subject 有好几种,这里可以使用最简单的 PublishSubject。订阅之后,一旦数据从一端传入,结果会里立刻从另一端输出。

源码里给了用法例子:

串行化

官方文档推荐我们:

如果你把 Subject 当作一个 Subscriber 使用,注意不要从多个线程中调用它的 onNext方法包括其它的on系列方法),这可能导致同时(非顺序)调用,这会 违反Observable协议,给 Subject 的结果增加了不确定性。

要避免此类问题,你可以将 Subject 转换为一个 SerializedSubject ,类似于这样:

mySafeSubject = new SerializedSubject(myUnsafeSubject);

所以我们可以看到在 RxBus 初始化的时候我们做了这样一件事情:

private final Subject<Object, Object> BUS;private RxBus() {    BUS = new SerializedSubject<>(PublishSubject.create());
}

为了保证多线程调用中结果的确定性,我们按照官方推荐将 Subject 转换成了一个 SerializedSubject

SerializedSubject


该类同样是 Subject 的子类,这里贴出该类的构造方法。

我们发现,Subject 最后转化成了 SerializedObserver

SerializedObserver

When multiple threads are emitting and/or notifying they will be serialized by:

Allowing only one thread at a time to emit

Adding notifications to a queue if another thread is already emitting

Not holding any locks or blocking any threads while emitting

一次只会允许一个线程进行发送事物
如果其他线程已经准备就绪,会通知给队列
在发送事物中,不会持有任何锁和阻塞任何线程

通过介绍可以知道是通过 notifications 来进行并发处理的。

SerializedObserver 类中:

private final NotificationLite<T> nl = NotificationLite.instance();

重点看看 nlonNext() 方法里的使用:

NotificationLite

知道哪里具体调用了之后,我们再仔细看看 NotificationLite 

先来了解它到底是什么:

For use in internal operators that need something like materialize and dematerialize wholly within the implementation of the operator but don’t want to incur the allocation cost of actually creating {@link rx.Notification} objects for every {@link Observer#onNext onNext} and {@link Observer#onCompleted onCompleted}.

It’s implemented as a singleton to maintain some semblance of type safety that is completely non-existent.

大致意思是:作为一个单例类保持这种完全不存在的安全类型的表象。

刚我们在 SerializedObserveronNext() 方法中看到 nl.accept(actual, o)

所以我们再深入到 accept() 方法中:

Unwraps the lite notification and calls the appropriate method on the {@link Observer}.

判断 lite 通知类别,通知 observer 执行适当方法。

通过 NotificationLite 类图可以看到有三个标识:

  • ON_NEXT_NULL_SENTINEL (onNext 标识)

  • ON_COMPLETED_SENTINEL (onCompleted 标识)

  • OnErrorSentinel (onError 标识)

Observer 回调一致。通过分析得知 accept() 就是通过标识来判断,然后调用 Observer 相对应的方法。

CompositeSubscription

RxBus 这辆”兰博基尼”与 CompositeSubscription 车间搭配更好。

构造函数:

内部是初始化了一个 HashSet ,按照哈希算法来存取集合中的对象,存取速度比较快,并且没有重复对象。

所以我们推荐在基类里实例化一个 CompositeSubscription 对象,使用 CompositeSubscription 来持有所有的 Subscriptions ,然后在 onDestroy()或者 onDestroyView() 里取消所有的订阅。

参考文章

http://blog.csdn.net/lzyzsd/article/details/45033611

https://mcxiaoke.gitbooks.io/rxdocs/content/Subject.html

熄火休息

能力有限,文章错误还望指出,有任何问题都欢迎讨论 :)

最后送上我的女神 Gakki (是投稿作者的,不是我的), 开心最好 ( ´͈v `͈ )◞。


如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

上车请投币

赞赏

人赞赏

从 RxBus 这辆兰博基尼深入进去相关推荐

  1. 搜集整理的一些博客导航

    简介:第一次在CSDN上发表博客,将自己关注或者看过的一些博客整理了一下,其中包含了鸿神和郭神的全部博客,包括两位大神微信公众号推荐的博客,另外还有一些安卓开发社区的博客,后续每天都会更新这个导航,希 ...

  2. Android 常用开发功能 博客导航

    转载地址:http://blog.csdn.net/ciqing123/article/details/52931663?locationNum=16&fps=1 简介:第一次在CSDN上发表 ...

  3. 面试分享:一年经验初探阿里巴巴前端社招

    一般阿里社招都是招3-5年的P6+高级工程师,当初自己一年经验也没有想过有这个面试机会. 虽然没想着换工作,但是经常关注一些招聘网站的信息,某一天,在某boss上有个人找我,叫我发一下简历,我一看是阿 ...

  4. 新一代容器技术———Podman

    目录 一 容器技术简介 1.1容器定义 1.2 容器与虚拟机 1.3 容器特性 1.4 容器核心技术 1.5 Podman 下一代容器 二 配置部署Podman容器 2.1 安装容器相关软件 2.1. ...

  5. python学习 day7_字符串、列表的相关操作

    python学习day7_字符串的相关函数 字符串的相关操作 (1)字符串的拼接 + (2)字符串的重复 * (3)字符串跨行拼接 \ (4)字符串的索引(复习) (5)字符串的切片:(截取) 对字符 ...

  6. OSChina 周二乱弹 —— 将娱乐进行到底

    2019独角兽企业重金招聘Python工程师标准>>> 周二到了,请在后门下车,先下后上- 大早上的,OSCer 在公车上,在地铁上? 当然,也有土豪的 OSCer 在停车,壕在停车 ...

  7. 如何用副业搞垮一个打工人?

    --感谢零代码厂商明道云对原创内容的支持-- 作者| Mr.K   编辑| Emma 来源| 技术领导力(ID:jishulingdaoli) 我年轻的时候,喜欢装文艺,现在病好了,只喜欢钱. 因为鲁 ...

  8. About Yarn

    yarn的由来 故事会 About yarn yarn 优势 yarn组成成员 yarn工作流程(参考刘老板的决策) 资源入口 结束语 故事会 <–>在改革开放的风口浪尖,凭着小刘敢闯敢打 ...

  9. 2023 亲自经历面试的初中级java面试题(持续更新)

    面试题 基础题 集合 说一下list,set,map的区别. hashMap key是自己定义的类,有没复写过hashcode或者equals这些方法 ? 线程安全问题 List ArrayList ...

最新文章

  1. 106页的《Python进阶》中文版(附下载)!
  2. r 语言计算欧氏距离_一文搞懂常用R语言统计值计算:打倒描述性统计拦路虎
  3. js中document.getElementById(ID)与document.getElementsByName(Name)的区别
  4. Android ListView异步加载图片乱序问题,原因分析及解决方案
  5. Exchange Server 2016管理系列课件05.邮件转发功能
  6. Spring MVC普通类或工具类中调用service报空空指针的解决办法(调用service报java.lang.NullPointerException)...
  7. qt给qdialog加一个滚动条_这些小程序技巧,你敢说你一个用不到?
  8. 生成n*n蛇形矩阵的算法
  9. 【MATLAB】(三)MATLAB在高等数学中的应用
  10. VC2008界面编程
  11. 程序猿崛起2——互联网时代下的新潮流和新活法
  12. sql中字符串转换成日期
  13. 麒麟V10系统-系统激活点击按钮无响应
  14. 2022年秋招 Java后端程序员如何应对面试?
  15. e的近似求解方法matlab,3X^2-E^X并用matlab切线法求出所有实根的近似值,源程序
  16. 双千兆和全千兆有什么区别?_千兆字节,太字节和PB有多少?
  17. Redis的下载与安装(windows系统)
  18. 干货分享!杭州知名SEO公司清法网络告诉你如何玩转小红书
  19. 用腾讯云阿里云搭建自己的个人网站
  20. sublime text_取消自动换行/启用自动换行

热门文章

  1. 用python编程 商品打折怎么计算_(特价书)从问题到程序:用Python学编程和计算
  2. Python制作微信二维码(动态+静态)
  3. 华宇智能数据官网全新上线,赋能行业数字化转型
  4. 【电影评价】——可爱的电影适合可爱的你!!!一直更新中
  5. RGW Bucket Shard优化
  6. 在linux系统中使用WoeUSB工具制作U盘启动盘
  7. 【Arduino】坐姿检测器
  8. 工作学习正确坐姿坐姿提升注意力
  9. 【record】1、FS-I6设置与对码
  10. 〖Python 数据库开发实战 - MySQL篇㉙〗- MySQL 字符函数