O artigo discutirá 
UndeliverableException no 
RxJava2 versão 
2.0.6 e posterior. Se alguém colidiu e não conseguiu descobrir ou não ouviu nada sobre esse problema, peço um gato. Eles solicitaram a tradução de problemas na 
production após a transição de 
RxJava1 para 
RxJava2 . O original foi escrito em 28 de dezembro de 2017, mas é melhor descobrir tarde do que nunca.
Todos somos bons desenvolvedores e detectamos erros no 
onError quando usamos o 
RxJava . Isso significa que nos protegemos de falhas de aplicativos, certo?
Não, não é verdade.Abaixo, veremos alguns exemplos nos quais o aplicativo 
RxJava devido ao 
RxJava , mesmo que o 
onError implementado corretamente.
Manipulador de erro básico no RxJava
RxJava usa 
RxJavaPlugins.onError como o manipulador de erros base. Ele lida com todos os erros que não podem ser entregues ao assinante. Por padrão, todos os erros são enviados a ele, para que falhas críticas do aplicativo possam ocorrer.
2.0.6 descrevem este comportamento:
Um dos objetivos do design 2.x é a falta de erros perdidos. Às vezes, uma sequência termina ou é cancelada antes que a fonte aumente onError . Nesse caso, o erro não tem para onde ir e é enviado para RxJavaPlugins.onError
Se o RxJava não tiver um manipulador de erros básico, esses erros serão ocultados para nós e os desenvolvedores ficarão no escuro sobre possíveis problemas no código.
A partir da versão 
2.0.6 , 
RxJavaPlugins.onError tenta ser mais inteligente e compartilha erros de biblioteca / implementação e situações em que um erro não pode ser entregue. Os erros atribuídos à categoria de "bugs" são chamados como são, enquanto os demais são agrupados em 
UndeliverableException e depois chamados. Você pode ver toda essa lógica 
aqui ( 
isBug onError e 
isBug ).
Um dos principais erros dos novatos no 
RxJava OnErrorNotImplementedException é o 
OnErrorNotImplementedException . Este erro ocorre se 
observable causar um erro e o método 
onError não estiver implementado no assinante. Este erro é um exemplo de erro que, para o manipulador de erros básico, 
RxJava é um "bug" e não se transforma em uma 
UndeliverableException .
UndeliverableException
Como os erros relacionados a "bugs" são fáceis de corrigir, não iremos nos deter neles. Os erros que o 
RxJava envolve em uma 
UndeliverableException são mais interessantes, pois nem sempre é óbvio o motivo pelo qual o erro não pode ser entregue ao 
onError .
Os casos em que isso pode acontecer dependem do que as fontes e assinantes fazem especificamente. Consideraremos exemplos abaixo, mas, em geral, podemos dizer que esse erro ocorre se não houver assinante ativo para quem o erro possa ser entregue.
Exemplo com zipWith ()
A primeira opção na qual você pode gerar uma 
UndeliverableException é a 
zipWith .
 val observable1 = Observable.error<Int>(Exception()) val observable2 = Observable.error<Int>(Exception()) val zipper = BiFunction<Int, Int, String> { one, two -> "$one - $two" } observable1.zipWith(observable2, zipper) .subscribe( { System.out.println(it) }, { it.printStackTrace() } ) 
Combinamos duas fontes juntas, cada uma delas causando um erro. O que esperamos? Podemos supor que 
onError será chamado duas vezes, mas isso contradiz 
a especificação de Reactive streams .
Após uma única chamada para um evento do terminal ( onError , onCompelete ), é necessário que não sejam feitas mais chamadas
Acontece que, com uma única chamada para 
onError segunda chamada não é mais possível. O que acontece quando ocorre um segundo erro na fonte? Ele será entregue ao 
RxJavaPlugins.onError .
Uma maneira fácil de entrar nessa situação é usar o 
zip para combinar chamadas de rede (por exemplo, duas chamadas de 
Retrofit retornando 
Observable ). Se ocorrer um erro nas duas chamadas (por exemplo, não há conexão com a Internet), ambas as fontes causarão erros, a primeira delas cairá na implementação 
onError e a segunda será entregue ao manipulador de erros base ( 
RxJavaPlugins.onError ).
Exemplo de ConnectableObservable sem assinantes
ConnectableObservable também pode gerar uma 
UndeliverableException . Vale lembrar que o 
ConnectableObservable gera eventos independentemente da presença de assinantes ativos, basta chamar o método 
connect() . Se ocorrer um erro no 
ConnectableObservable quando não houver assinantes, ele será entregue ao manipulador de erros base.
Aqui está um exemplo bastante inocente que pode causar esse erro:
 someApi.retrofitCall()  
Se 
someApi.retrofitCall() causar um erro (por exemplo, não há conexão com a Internet), o aplicativo 
RxJava , pois o erro de rede será entregue ao 
RxJava erros base do 
RxJava .
Este exemplo parece fictício, mas é muito fácil entrar em uma situação em que o 
ConnectableObservable ainda está conectado, mas não possui assinantes. Me deparei com isso ao usar o 
autoConnect() ao chamar uma API. 
autoConnect() não desativa automaticamente o 
Observable . 
onStop a inscrição no método 
onStop da 
Activity , mas o resultado da chamada de rede retornou após a destruição da 
Activity e o aplicativo 
UndeliverableException com 
UndeliverableException .
Tratamento de erros
Então, o que fazer com esses erros?
O primeiro passo é examinar os erros que ocorrem e tentar determinar o que os causa. Idealmente, se você puder corrigir o problema em sua origem para impedir que o erro seja 
RxJavaPlugins.onError ao 
RxJavaPlugins.onError .
A solução para o exemplo 
zipWith é pegar uma ou ambas as fontes e implementar 
um dos métodos para detectar erros nelas. Por exemplo, você pode usar 
onErrorReturn para passar o valor padrão em vez de um erro.
O exemplo do 
ConnectableObservable é mais simples de corrigir - basta desconectar o 
Observable quando o último assinante cancelar a inscrição. 
autoConnect() , por exemplo, possui uma implementação sobrecarregada que 
autoConnect() uma função que captura o tempo de conexão ( 
mais pode ser visto aqui ).
Outra maneira de resolver o problema é substituir o manipulador de erros base pelo seu. O 
RxJavaPlugins.setErrorHandler(Consumer<Throwable>) o ajudará com isso. Se esta é a solução certa para você, você pode capturar todos os erros enviados para 
RxJavaPlugins.onError e manipulá-los como achar melhor. Essa solução pode ser bastante complicada - lembre-se de que o 
RxJavaPlugins.onError recebe erros de todos os fluxos do 
RxJava no aplicativo.
Se você criar manualmente seu 
Observable , poderá chamar 
emitter.tryOnError() vez de 
emitter.tryOnError() . Este método relata um erro apenas se o fluxo não for encerrado e tiver assinantes. Lembre-se de que este método é experimental.
A moral deste artigo é que você não pode ter certeza de que não há erros ao trabalhar com o RxJava se você simplesmente implementou o 
onError nos assinantes. Você deve estar ciente das situações em que os erros podem não estar disponíveis para os assinantes e garantir que essas situações sejam tratadas.