RxRelay é mágico? Assunto vs RxRelay





Na comunidade Android, encontrei três tipos de desenvolvedores que encontraram o RxRelay:



  1. Aqueles que não entendem porque RxRelay é usado em seu projeto, porque é necessário e como ele difere do Assunto
  2. Aqueles que pensam que RxRelay "engole" erros ou "após o erro RxRelay ter ocorrido, ele continuará a funcionar, mas o Assunto não" (a mesma mágica)
  3. Aqueles que realmente sabem o que é RxRelay.


Embora os dois primeiros tipos sejam mais comuns, decidi escrever um artigo que ajudará você a entender como funciona o RxRelay e verificar suas propriedades "mágicas".



Se você estiver usando RxJava, provavelmente usará Subject ou RxRelay para lançar eventos de uma entidade para outra ou fazer código reativo de código imperativo.



Vamos dar uma olhada no # 2 e ver qual é a diferença entre RxRelay e Assunto. Portanto, temos duas assinaturas para um relé, quando clicamos no botão, enviamos um para este relé.



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


Clicamos no botão três vezes seguidas e vemos esse log.

D / teste: Cadeia com erro: onNext

D / test: Cadeia sem erro: onNext



D / test: Cadeia com erro: onError

D / test: Cadeia sem erro: onNext



D / test: Cadeia sem erro: onNext



Se você substituir a variável RxRelay por PublishSubject, o log não será alterado. Eis o motivo:



no primeiro clique, colocamos os dados em nosso relé. Ambos os assinantes são acionados.



No segundo clique na cadeia, o primeiro assinante (descartável1) obtém um erro.



No terceiro clique, o primeiro descartável1 não dispara mais, pois recebeu o estado terminal onError. Então, apenas o segundo descartável2 funcionará.



Esse será o caso com Assunto e RxRelay. Deixe-me lembrá-lo que no rx os erros descem na cadeia até o assinante (downstream) e acima do local onde ocorreram, eles não chegam. Acabamos verificando se o encadeamento baseado em RxRelay não funcionava após a ocorrência de um erro.



Portanto, se não há diferença no comportamento de Subject e RxRelay, qual é a diferença?



Aqui está o que o próprio desenvolvedor escreve no README no github:

“Basicamente: um assunto, exceto sem a capacidade de chamar onComplete ou onError.”



Ou seja, é apenas um Subject sem os métodos onComplete e onError, até mesmo o código-fonte das classes é quase o mesmo. Se chamarmos esses métodos no Assunto, ele deixará de funcionar, pois receberá um estado terminal. Portanto, o autor da biblioteca decidiu que valia a pena remover esses métodos, pois os desenvolvedores que não conhecem essa propriedade Subject podem chamá-los acidentalmente.



Conclusão: a única diferença entre RxRelay e Subject é a ausência de dois métodos onComplete e onError, de forma que o desenvolvedor não pode chamar o estado do terminal.



All Articles