Convertendo APIs síncronas e assíncronas em observáveis ​​usando RxJava2

Convertendo APIs síncronas e assíncronas em observáveis ​​usando RxJava2

1. Visão geral

Neste tutorial, aprenderemos os operadoreshow to transform traditional synchronous and asynchronous APIs into Observables using RxJava2.

Criaremos algumas funções simples que nos ajudarão a discutir esses operadores em detalhes.

2. Dependências do Maven

Primeiro, temos que adicionarRxJava2 eRxJava2Extensions como dependências Maven:


    io.reactivex.rxjava2
    rxjava
    2.2.2


    com.github.akarnokd
    rxjava2-extensions
    0.20.4

3. Os operadores

RxJava2 definea whole lot of operators para vários casos de uso de programação reativa.

Mas iremos discutir apenas alguns operadores que são comumente usados ​​para converter métodos síncronos ou assíncronos emObservables com base em sua natureza. These operators take functions as arguments and emit the value returned from that function.

Juntamente com os operadores normais, o RxJava2 define mais alguns operadores para funcionalidades estendidas.

Vamos explorar como podemos usar esses operadores para converter métodos síncronos e assíncronos.

4. Conversão de Método Síncrono

4.1. UsandofromCallable()

Esse operador retorna umObservable que, quando um assinante se inscreve nele, invoca a função passada como o argumento e emite o valor retornado dessa função. Vamos criar uma função que retorna um inteiro e transformá-lo:

AtomicInteger counter = new AtomicInteger();
Callable callable = () -> counter.incrementAndGet();

Agora, vamos transformá-lo em umObservablee testá-lo inscrevendo-se nele:

Observable source = Observable.fromCallable(callable);

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(i);
    assertEquals(i, counter.get());
}

The fromCallable() operator executes the specified function lazily each time when the wrapped Observable gets subscribed. Para testar esse comportamento, criamos vários assinantes usando um loop.

Como os fluxos reativos são assíncronos por padrão, o assinante retornará imediatamente. Na maioria dos cenários práticos, a função de chamada terá algum tipo de atraso para concluir sua execução. Então,we’ve added a maximum wait time of five seconds antes de testar o resultado de nossa função chamável.

Observe também que usamos o métodoObservable'stest(). This method is handy when testing Observables. Ele cria umaTestObserver areia inscreve-se em nossoObservable.

4.2. Usandostart()

O operadorstart() faz parte do móduloRxJava2Extension. Ele invocará a função especificada de forma assíncrona e retornará umObservable que emite o resultado:

Observable source = AsyncObservable.start(callable);

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(1);
    assertEquals(1, counter.get());
}

A função é chamada imediatamente, não sempre que um assinante assina osObservable resultantes. Multiple subscriptions to this observable observe the same return value.

5. Conversão de Método Assíncrono

5.1. UsandofromFuture()

Como sabemos, a maneira mais comum de criar um método assíncrono em Java é usando a implementaçãoFuture. O métodofromFuture levaFuture como argumento e emite o valor obtido do métodoFuture.get().

Primeiro, vamos tornar a função que criamos anteriormente assíncrona:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(callable);

A seguir, vamos fazer o teste transformando-o:

Observable source = Observable.fromFuture(future);

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(1);
    assertEquals(1, counter.get());
}
executor.shutdown();

E observe mais uma vez que cada assinatura observa o mesmo valor de retorno.

Agora, o métododispose() deObservable é realmente útil quando se trata de prevenção de vazamento de memória. Mas, neste caso, ele não cancelará o futuro devido à natureza de bloqueio deFuture.get().

Portanto, podemos garantir o cancelamento do futuro pela funçãocombining the doOnDispose() do métodosource observável e o métodocancel emfuture:

source.doOnDispose(() -> future.cancel(true));

5.2. UsandostartFuture()

Como o nome indica, este operador iniciará oFuture especificado imediatamente e emitirá o valor de retorno quando um assinante o assinar. Ao contrário do operadorfromFuture, que armazena em cache o resultado para o próximo uso,this operator will execute the asynchronous method each time when it gets subscribed:

ExecutorService executor = Executors.newSingleThreadExecutor();
Observable source = AsyncObservable.startFuture(() -> executor.submit(callable));

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(i);
    assertEquals(i, counter.get());
}
executor.shutdown();

5.3. UsandodeferFuture()

This operator aggregates multiple Observables returned from a Future method and returns a stream of return values obtained from each Observable. Isso iniciará a função de fábrica assíncrona passada sempre que um novo assinante se inscrever.

Então, vamos primeiro criar a função de fábrica assíncrona:

List list = Arrays.asList(new Integer[] { counter.incrementAndGet(),
  counter.incrementAndGet(), counter.incrementAndGet() });
ExecutorService exec = Executors.newSingleThreadExecutor();
Callable> callable = () -> Observable.fromIterable(list);

E então podemos fazer um teste rápido:

Observable source = AsyncObservable.deferFuture(() -> exec.submit(callable));
for (int i = 1; i < 4; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(1,2,3);
}
exec.shutdown();

6. Conclusão

Neste tutorial, aprendemos como transformar os métodos síncronos e assíncronos em observáveis ​​RxJava2.

Claro, os exemplos que mostramos aqui são as implementações básicas. Mas podemos usar o RxJava2 para aplicativos mais complexos, como streaming de vídeo e aplicativos para os quais precisamos enviar grandes quantidades de dados em partes.

Como de costume, todos os exemplos curtos que discutimos aqui podem ser encontrados emGithub project.