在Android社区中,我遇到了三种使用RxRelay的开发人员:
- 那些不理解为什么在他们的项目中使用RxRelay的人,为什么需要它以及它与Subject有何不同
- 那些认为RxRelay会“吞咽”错误或“在RxRelay错误发生之后,它将继续起作用,但是Subject不会起作用”的人(同样的魔术)
- 那些真正知道RxRelay是什么的人。
尽管前两种类型较为常见,但我还是决定写一篇文章,以帮助您了解RxRelay的工作原理并检查其“魔术”属性。
如果您使用的是RxJava,则可能使用Subject或RxRelay将事件从一个实体扔到另一个实体,或者从命令式代码中生成响应式代码。
让我们查看#2,看看RxRelay和Subject之间有什么区别。因此,我们有两个订阅到一个中继,当我们单击按钮时,我们将一个订阅推到该中继。
class MainActivity : AppCompatActivity() {
private val relay = PublishRelay.create<Int>()
private var isError: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val disposable1 = relay
.map {
if (isError) {
isError = false
throw Exception()
} else {
isError = true
}
}.subscribe(
{
Log.d("test", " : onNext")
},
{
Log.d("test", " : onError")
}
)
val disposable2 = relay
.subscribe(
{
Log.d("test", " : onNext")
},
{
Log.d("test", " : onError")
}
)
btn.setOnClickListener {
relay.accept(1)
}
}
}
我们连续三次单击按钮,然后看到这样的日志。
D /测试:有错误的
链:onNext
D /测试:有错误的链:onNext D /测试:有错误的链:onError
D /测试:无错误的链:onNext
D /测试:无错误的链:onNext
如果将RxRelay变量替换为PublishSubject,日志不会更改。原因如下:
第一次单击时,我们将数据推送到中继中。两个订户都被触发。
在链中第二次单击时,第一个订户(disposable1)收到错误。
第三次单击时,第一个disable1不再触发,因为它收到了终端状态onError。然后,只有第二个一次性用品2起作用。
主题和RxRelay就是这种情况。让我提醒您,在rx错误中,错误沿着链子到达订户(下游),而在错误发生的地方上方却没有得到。我们最终检查了在发生错误后基于RxRelay的链接无法正常工作。
因此,如果Subject和RxRelay的行为没有差异,那么它们有什么区别?
这是开发人员本人在github上的README中写的内容:
“基本上:一个主题,除了不能调用onComplete或onError之外。”
也就是说,它只是一个主题,没有onComplete和onError方法,即使类的源代码也几乎相同。如果我们在Subject上调用这些方法,则它将停止工作,因为它将收到终端状态。因此,该库的作者认为值得删除这些方法,因为那些不了解此Subject属性的开发人员可能会意外地调用它们。
结论:RxRelay和Subject之间的唯一区别是缺少两个方法onComplete和onError,因此开发人员无法调用终端状态。