RxRelay是魔术吗?主题vs RxRelay





在Android社区中,我遇到了三种使用RxRelay的开发人员:



  1. 那些不理解为什么在他们的项目中使用RxRelay的人,为什么需要它以及它与Subject有何不同
  2. 那些认为RxRelay会“吞咽”错误或“在RxRelay错误发生之后,它将继续起作用,但是Subject不会起作用”的人(同样的魔术)
  3. 那些真正知道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,因此开发人员无法调用终端状态。



All Articles