Implementando operadores personalizados no RxJava
1. Visão geral
Neste tutorial rápido, mostraremos como escrever um operador personalizado usandoRxJava.
Discutiremos como construir este operador simples, bem como um transformador - tanto como uma classe ou como uma função simples.
2. Configuração do Maven
Primeiro, precisamos ter certeza de que temos a dependênciarxjava empom.xml:
io.reactivex
rxjava
1.3.0
Podemos verificar a versão mais recente derxjava emMaven Central.
3. Operador Customizado
We can create our custom operator by implementing Operator interface, no exemplo a seguir, implementamos um operador simples para remover caracteres não alfanuméricos de umString:
public class ToCleanString implements Operator {
public static ToCleanString toCleanString() {
return new ToCleanString();
}
private ToCleanString() {
super();
}
@Override
public Subscriber super String> call(final Subscriber super String> subscriber) {
return new Subscriber(subscriber) {
@Override
public void onCompleted() {
if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}
@Override
public void onError(Throwable t) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(t);
}
}
@Override
public void onNext(String item) {
if (!subscriber.isUnsubscribed()) {
final String result = item.replaceAll("[^A-Za-z0-9]", "");
subscriber.onNext(result);
}
}
};
}
}
No exemplo acima, precisamos verificar se o assinante está inscrito antes de aplicar nossa operação e emitir o item, pois será desnecessário.
We are also restricting instance creation only to static factory methods to achieve a more user-friendly readability ao encadear métodos e usar a importação estática.
E agora, podemos usar o operadorlift para encadear nosso operador personalizado facilmente com outros operadores:
observable.lift(toCleanString())....
Aqui está um teste simples do nosso operador personalizado:
@Test
public void whenUseCleanStringOperator_thenSuccess() {
List list = Arrays.asList("john_1", "tom-3");
List results = new ArrayList<>();
Observable observable = Observable
.from(list)
.lift(toCleanString());
observable.subscribe(results::add);
assertThat(results, notNullValue());
assertThat(results, hasSize(2));
assertThat(results, hasItems("john1", "tom3"));
}
4. Transformador
Também podemos criar nosso operador implementando a interfaceTransformer:
public class ToLength implements Transformer {
public static ToLength toLength() {
return new ToLength();
}
private ToLength() {
super();
}
@Override
public Observable call(Observable source) {
return source.map(String::length);
}
}
Observe que usamos o transformadortoLength para transformar nosso observável deString para seu comprimento emInteger.
Precisaremos de um operadorcompose para usar nosso transformador:
observable.compose(toLength())...
Aqui está um teste simples:
@Test
public void whenUseToLengthOperator_thenSuccess() {
List list = Arrays.asList("john", "tom");
List results = new ArrayList<>();
Observable observable = Observable
.from(list)
.compose(toLength());
observable.subscribe(results::add);
assertThat(results, notNullValue());
assertThat(results, hasSize(2));
assertThat(results, hasItems(4, 3));
}
Olift(Operator) opera nos assinantes do observável, mascompose(Transformer) trabalha no próprio observável.
Quando criamos nosso operador personalizado, devemos escolherTransformer se quisermos operar no observável como um todo e escolherOperator se quisermos operar nos itens emitidos pelo observável
5. Operador personalizado como função
Podemos implementar nosso operador personalizado como uma função em vez depublic class:
Operator cleanStringFn = subscriber -> {
return new Subscriber(subscriber) {
@Override
public void onCompleted() {
if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}
@Override
public void onError(Throwable t) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(t);
}
}
@Override
public void onNext(String str) {
if (!subscriber.isUnsubscribed()) {
String result = str.replaceAll("[^A-Za-z0-9]", "");
subscriber.onNext(result);
}
}
};
};
E aqui está o teste simples:
List results = new ArrayList<>();
Observable.from(Arrays.asList("[email protected]", "or-an?ge"))
.lift(cleanStringFn)
.subscribe(results::add);
assertThat(results, notNullValue());
assertThat(results, hasSize(2));
assertThat(results, hasItems("apple", "orange"));
Da mesma forma para o exemploTransformer:
@Test
public void whenUseFunctionTransformer_thenSuccess() {
Transformer toLengthFn = s -> s.map(String::length);
List results = new ArrayList<>();
Observable.from(Arrays.asList("apple", "orange"))
.compose(toLengthFn)
.subscribe(results::add);
assertThat(results, notNullValue());
assertThat(results, hasSize(2));
assertThat(results, hasItems(5, 6));
}
6. Conclusão
Neste artigo, mostramos como escrever nossos operadores RxJava.
E, como sempre, o código-fonte completo pode ser encontradoover on GitHub.