Combinando os Completables RxJava
1. Visão geral
Neste tutorial, vamos brincar com o tipoRxJava’sCompletable, que representa um resultado de cálculo sem um valor real.
2. Dependência RxJava
Vamos incluir a dependência RxJava 2 em nosso projeto Maven:
io.reactivex.rxjava2
rxjava
2.2.2
Normalmente, podemos encontrar a versão mais recente emMaven Central.
3. Tipo Completável
Completableis similar to Observable with the only exception that the former emits either completion or error signals but no items. A classeCompletable contém vários métodos convenientes para criar ou obtê-la de diferentes fontes reativas.
Podemos gerar uma instância que é concluída imediatamente usandoCompletable.complete().
Então, podemos observar seu estado usandoDisposableCompletableObserver:
Completable
.complete()
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
System.out.println("Completed!");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
});
Além disso, podemos construir uma instânciaCompletable deCallable, Action, and Runnable:
Completable.fromRunnable(() -> {});
Além disso, podemos obter instâncias deCompletable de outros tipos usandoCompletable.from() ou chamandoignoreElement() emMaybe,Single,Flowable eObservablepróprias fontes:
Flowable flowable = Flowable
.just("request received", "user logged in");
Completable flowableCompletable = Completable
.fromPublisher(flowable);
Completable singleCompletable = Single.just(1)
.ignoreElement();
4. EncadeandoCompletables
Podemos empregar o encadeamento deCompletables em muitos casos de uso do mundo real quando nos preocupamos apenas com o sucesso da operação:
-
Ações do tipo tudo ou nada, como fazer uma solicitação PUT para atualizar um objeto remoto seguido por uma atualização do banco de dados local após o sucesso
-
Registro e diário pós-factum
-
Orquestração de várias ações, por exemplo executando um trabalho de análise após a conclusão de uma ação de ingestão
Manteremos exemplos simples e independentes de problemas. Considere que temos várias instâncias deCompletable:
Completable first = Completable
.fromSingle(Single.just(1));
Completable second = Completable
.fromRunnable(() -> {});
Throwable throwable = new RuntimeException();
Completable error = Single.error(throwable)
.ignoreElement();
To combine two Completables into a single one, we can use the andThen() operator:
first
.andThen(second)
.test()
.assertComplete();
Podemos encadear quantosCompletables forem necessários. Ao mesmo tempo,if at least one of the sources fails to complete, resulting Completable won’t fire onComplete() as well:
first
.andThen(second)
.andThen(error)
.test()
.assertError(throwable);
Além disso,if one of the sources is infinite or doesn’t reach onComplete for some reason, the resulting Completable will never fire onComplete() nor onError() as well.
Ainda bem que ainda podemos testar esse cenário:
...
.andThen(Completable.never())
.test()
.assertNotComplete();
5. Compondo Série de Completáveis
Imagine que temos um monte deCompletables. Como caso de uso prático, suponha que precisemos registrar um usuário em vários subsistemas separados.
To join all Completables into a single one, we can use the merge() family of methods. A operadoramerge() permite a assinatura de todas as fontes.
A instância resultantecompletes once all of the sources are completed. Além disso, termina comonError quando qualquer uma das fontes emite um erro:
Completable.mergeArray(first, second)
.test()
.assertComplete();
Completable.mergeArray(first, second, error)
.test()
.assertError(throwable);
Vamos passar para um caso de uso ligeiramente diferente. Digamos que precisamos executar uma ação para cada elemento obtido de umFlowable.
Então, queremos um únicoCompletable para a conclusão do upstream e para todas as ações de nível de elemento. O operadorflatMapCompletable () vem para ajudar neste caso:
Completable allElementsCompletable = Flowable
.just("request received", "user logged in")
.flatMapCompletable(message -> Completable
.fromRunnable(() -> System.out.println(message))
);
allElementsCompletable
.test()
.assertComplete();
Da mesma forma, o método acima está disponível para o resto das classes reativas de base comoObservable,Maybe ouSingle.
Como um contexto prático paraflatMapCompletable(), poderíamos pensar em decorar cada item com algum efeito colateral. Podemos escrever uma entrada de log por elemento concluído ou fazer uma captura instantânea de armazenamento a cada ação bem-sucedida.
Finalmente,we may need to construct a Completable from a couple of other sources and get it terminated as soon as either of them completes. É aí que os operadoresamb podem ajudar.
O prefixoamb é uma abreviação de “ambíguo”, implicando na incerteza sobre qualCompletable exatamente é completado. Por exemplo,ambArray():
Completable.ambArray(first, Completable.never(), second)
.test()
.assertComplete();
Observe que oCompletable acima também pode terminar comonError() em vez deonComplete(), dependendo de qual fonte termina primeiro:
Completable.ambArray(error, first, second)
.test()
.assertError(throwable);
Além disso, assim que a primeira fonte terminar, é garantido que as fontes restantes serão descartadas.
Isso significa que todos osCompletables restantes em execução serão interrompidos por meio deDisposable.dispose()e osCompletableObservers correspondentes serão cancelados.
Em relação a um exemplo prático, podemos usaramb() quando transmitimos um arquivo de backup para vários armazenamentos remotos equivalentes. E concluímos o processo assim que o primeiro melhor backup terminar ou repetimos o processo por erro.
6. Conclusão
Neste artigo, revisamos brevemente o tipoCompletable de RxJava.
Começamos com diferentes opções para obter instâncias deCompletable e depois encadeamos e compusemosCompletables usando os operadoresandThen(), merge(), flatMapCompletable(), andamb…().
Podemos encontrar a fonte para todas as amostras de códigoover on GitHub.