RxJava Hooks

RxJava Hooks

1. Visão geral

Neste tutorial, aprenderemos sobreRxJava ganchos. Estaremos criando pequenos exemplos para demonstrar como os ganchos funcionam em diferentes situações.

2. O que são RxJava Hooks?

Como o nome indica, os ganchos RxJava nos permitemhook into the lifecycle of Observable, _Completable, Maybe, Flowable, and * Single *. In addition, RxJava allows us to add lifecycle hooks to the schedulers returned by Schedulers._ Além disso, podemos especificar um manipulador de erro global também usando os ganchos.

No RxJava 1, a classeRxJavaHooks é usada para definir os ganchos. Mas, o mecanismo de conexão é completamente reescrito no RxJava 2. Now the class RxJavaHooks is no longer available to define the hooks. Instead, we should use RxJavaPlugins to implement the lifecycle hooks.

A classeRxJavaPlugins possui vários métodos setter para definir os ganchos. Esses ganchos são globais. Depois de configurados, temos que chamar o métodoreset() da classeRxJavaPlugins ou chamar o método setter para o gancho individual para removê-lo.

3. Gancho para tratamento de erros

Podemos usar o métodosetErrorHandler( ) para lidar com os erros que não podem ser emitidos porque o ciclo de vida do downstream já atingiu seu estado terminal. Vamos ver como podemos implementar um manipulador de erros e testá-lo:

RxJavaPlugins.setErrorHandler(throwable -> {
    hookCalled = true;
});

Observable.error(new IllegalStateException()).subscribe();

assertTrue(hookCalled);

Nem todas as exceções são lançadas como estão. No entanto, o RxJava verificará se o erro lançado é um dos casos de bug já nomeados que devem ser transmitidos no estado em que se encontram, caso contrário, serão agrupados emUndeliverableException. As exceções nomeadas como casos de erro são:

  • OnErrorNotImplementedException - quando o usuário se esquece de adicionar o manipuladoronError no métodosubscribe()

  • MissingBackpressureException – devido a um bug do operador ouonNext simultâneo

  • IllegalStateException – quando ocorrem violações gerais do protocolo

  • NullPointerException – exceção de ponteiro nulo padrão

  • IllegalArgumentException – devido a entrada inválida do usuário

  • CompositeException – devido a uma falha durante o tratamento de uma exceção

4. Ganchos paraCompletable

O RxJavaCompletable tem dois ganchos de ciclo de vida. Vamos dar uma olhada neles agora.

4.1. setOnCompletableAssembly

RxJava chamará este gancho quando instanciar operadores e fontes emCompletable. Podemos usar o objetoCompletable atual, fornecido como um argumento para a função de gancho, para qualquer operação nele:

RxJavaPlugins.setOnCompletableAssembly(completable -> {
    hookCalled = true;
    return completable;
});

Completable.fromSingle(Single.just(1));

assertTrue(hookCalled);

4.2. setOnCompletableSubscribe

RxJava chama esse gancho antes que um assinante se inscreva em umCompletable:

RxJavaPlugins.setOnCompletableSubscribe((completable, observer) -> {
    hookCalled = true;
    return observer;
});

Completable.fromSingle(Single.just(1)).test();

assertTrue(hookCalled);

5. Ganchos paraObservable

A seguir, vamos dar uma olhada nos três ganchos de ciclo de vida do RxJava paraObservable.

5.1. setOnObservableAssembly

RxJava chama este gancho quando instancia operadores e fontes emObservable:

RxJavaPlugins.setOnObservableAssembly(observable -> {
    hookCalled = true;
    return observable;
});

Observable.range(1, 10);

assertTrue(hookCalled);

5.2. setOnObservableSubscribe

RxJava chama este gancho antes que um assinante se inscreva em umObservable:

RxJavaPlugins.setOnObservableSubscribe((observable, observer) -> {
    hookCalled = true;
    return observer;
});

Observable.range(1, 10).test();

assertTrue(hookCalled);

5.3. setOnConnectableObservableAssembly

Este gancho se destina aConnectableObservable. UmConnectableObservable é uma variante do próprioObservable. A única diferença é que ele não começa a emitir itens quando é inscrito, mas apenas quando seu métodoconnect() é chamado:

RxJavaPlugins.setOnConnectableObservableAssembly(connectableObservable -> {
    hookCalled = true;
    return connectableObservable;
});

ConnectableObservable.range(1, 10).publish().connect();

assertTrue(hookCalled);

6. Ganchos paraFlowable

Agora, vamos dar uma olhada nos ganchos de ciclo de vida definidos paraFlowable.

6.1. setOnFlowableAssembly

RxJava chama este gancho quando instancia operadores e fontes emFlowable:

RxJavaPlugins.setOnFlowableAssembly(flowable -> {
    hookCalled = true;
    return flowable;
});

Flowable.range(1, 10);

assertTrue(hookCalled);

6.2. setOnFlowableSubscribe

RxJava chama este gancho antes que um assinante assineFlowable:

RxJavaPlugins.setOnFlowableSubscribe((flowable, observer) -> {
    hookCalled = true;
    return observer;
});

Flowable.range(1, 10).test();

assertTrue(hookCalled);

6.3. setOnConnectableFlowableAssembly

RxJava chama esse gancho quando instancia operadores e fontes emConnectableFlowable. Como oConnectableObservable,ConnectableFlowable também começa a emitir itens apenas quando chamamos seu métodoconnect():

RxJavaPlugins.setOnConnectableFlowableAssembly(connectableFlowable -> {
    hookCalled = true;
    return connectableFlowable;
});

ConnectableFlowable.range(1, 10).publish().connect();

assertTrue(hookCalled);

6.4. setOnParallelAssembly

AParallelFlowable é para alcançar o paralelismo entre vários editores. RxJava chama o ganchosetOnParallelAssembly() quando instancia operadores e fontes emParallelFlowable:

RxJavaPlugins.setOnParallelAssembly(parallelFlowable -> {
    hookCalled = true;
    return parallelFlowable;
});

Flowable.range(1, 10).parallel();

assertTrue(hookCalled);

7. Ganchos paraMaybe

O emissorMaybe tem dois ganchos definidos para controlar seu ciclo de vida.

7.1. setOnMaybeAssembly

RxJava chama este gancho quando instancia operadores e fontes emMaybe:

RxJavaPlugins.setOnMaybeAssembly(maybe -> {
    hookCalled = true;
    return maybe;
});

Maybe.just(1);

assertTrue(hookCalled);

7.2. setOnMaybeSubscribe

RxJava chama este gancho antes que um assinante assineMaybe:

RxJavaPlugins.setOnMaybeSubscribe((maybe, observer) -> {
    hookCalled = true;
    return observer;
});

Maybe.just(1).test();

assertTrue(hookCalled);

8. Ganchos paraSingle

RxJava define os dois ganchos básicos para o emissorSingle também.

8.1. setOnSingleAssembly

RxJava chama este gancho quando instancia operadores e fontes emSingle:

RxJavaPlugins.setOnSingleAssembly(single -> {
    hookCalled = true;
    return single;
});

Single.just(1);

assertTrue(hookCalled);

8.2. setOnSingleSubscribe

RxJava chama este gancho antes que um assinante assineSingle:

RxJavaPlugins.setOnSingleSubscribe((single, observer) -> {
    hookCalled = true;
    return observer;
});

Single.just(1).test();

assertTrue(hookCalled);

9. Ganchos paraSchedulers

Como os emissores RxJava,Schedulers também tem vários ganchos para controlar seu ciclo de vida. RxJava define um gancho comum que é chamado quando usamos qualquer tipo deSchedulers. Além disso, é possível implementar ganchos que são específicos para váriosSchedulers.

9.1. setScheduleHandler

RxJava chama esse gancho quando usamos qualquer um dos agendadores para uma operação:

RxJavaPlugins.setScheduleHandler((runnable) -> {
    hookCalled = true;
    return runnable;
});

Observable.range(1, 10)
  .map(v -> v * 2)
  .subscribeOn(Schedulers.single())
  .test();

hookCalled = false;

Observable.range(1, 10)
  .map(v -> v * 2)
  .subscribeOn(Schedulers.computation())
  .test();

assertTrue(hookCalled);

Como repetimos a operação com os agendadoressingle()ecomputation(), quando executarmos isso, o caso de teste imprimirá a mensagem duas vezes no console.

9.2. Ganchos paraComputation Scheduler

O agendador de computação tem dois ganchos - a saber,setInitComputationSchedulerHandleresetComputationSchedulerHandler.

Quando RxJava inicializa um agendador de computação, ele chama o gancho que definimos usando a funçãosetInitComputationSchedulerHandler. E, além disso, ele chama o gancho que definimos usandosetComputationSchedulerHandler function quando agendamos uma tarefa comSchedulers.computation():

RxJavaPlugins.setInitComputationSchedulerHandler((scheduler) -> {
    initHookCalled = true;
    return scheduler.call();
});

RxJavaPlugins.setComputationSchedulerHandler((scheduler) -> {
    hookCalled = true;
    return scheduler;
});

Observable.range(1, 10)
  .map(v -> v * 2)
  .subscribeOn(Schedulers.computation())
  .test();

assertTrue(hookCalled && initHookCalled);

9.3. Ganchos paraIO Scheduler

O planejadorIO também tem dois ganchos - a saber,setInitIoSchedulerHandler esetIoSchedulerHandler:

RxJavaPlugins.setInitIoSchedulerHandler((scheduler) -> {
    initHookCalled = true;
    return scheduler.call();
});

RxJavaPlugins.setIoSchedulerHandler((scheduler) -> {
    hookCalled = true;
    return scheduler;
});

Observable.range(1, 10)
  .map(v -> v * 2)
  .subscribeOn(Schedulers.io())
  .test();

assertTrue(hookCalled && initHookCalled);

9.4. Ganchos paraSingle Scheduler

Agora, vamos ver os ganchos para o agendadorSingle:

RxJavaPlugins.setInitSingleSchedulerHandler((scheduler) -> {
    initHookCalled = true;
    return scheduler.call();
});

RxJavaPlugins.setSingleSchedulerHandler((scheduler) -> {
    hookCalled = true;
    return scheduler;
});

Observable.range(1, 10)
  .map(v -> v * 2)
  .subscribeOn(Schedulers.single())
  .test();

assertTrue(hookCalled && initHookCalled);

9.5. Ganchos paraNewThread Scheduler

Como outros planejadores, o planejadorNewThread também define dois ganchos:

RxJavaPlugins.setInitNewThreadSchedulerHandler((scheduler) -> {
    initHookCalled = true;
    return scheduler.call();
});

RxJavaPlugins.setNewThreadSchedulerHandler((scheduler) -> {
    hookCalled = true;
    return scheduler;
});

Observable.range(1, 15)
  .map(v -> v * 2)
  .subscribeOn(Schedulers.newThread())
  .test();

assertTrue(hookCalled && initHookCalled);

10. Conclusão

Neste tutorial, aprendemos quais são os vários ganchos de ciclo de vida do RxJava e como podemos implementá-los. Entre esses ganchos, o gancho para manipulação de erros é o mais notável. Porém, podemos usar outros para fins de auditoria, como registrar o número de assinantes e outros casos de uso específicos.

E, como de costume, todos os exemplos curtos que discutimos aqui podem ser encontradosover on GitHub.