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.