«1. Обзор
В этом кратком руководстве мы покажем, как написать собственный оператор с помощью RxJava.
Мы обсудим, как создать этот простой оператор, а также преобразователь — как класс или как простую функцию.
2. Конфигурация Maven
Во-первых, нам нужно убедиться, что у нас есть зависимость rxjava в pom.xml:
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
<version>1.3.0</version>
</dependency>
Мы можем проверить последнюю версию rxjava на Maven Central.
3. Пользовательский оператор
Мы можем создать наш собственный оператор, реализовав интерфейс оператора. В следующем примере мы реализовали простой оператор для удаления небуквенно-цифровых символов из строки:
public class ToCleanString implements Operator<String, String> {
public static ToCleanString toCleanString() {
return new ToCleanString();
}
private ToCleanString() {
super();
}
@Override
public Subscriber<? super String> call(final Subscriber<? super String> subscriber) {
return new Subscriber<String>(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);
}
}
};
}
}
В приведенном выше примере , нам нужно проверить, подписан ли подписчик, прежде чем применять нашу операцию и передавать ему элемент, поскольку в этом нет необходимости.
Мы также ограничиваем создание экземпляров только статическими фабричными методами, чтобы обеспечить более удобную для пользователя читаемость при цепочке методов и использовании статического импорта.
А теперь мы можем использовать оператор lift для простой связи нашего пользовательского оператора с другими операторами:
observable.lift(toCleanString())....
Вот простой тест нашего пользовательского оператора:
@Test
public void whenUseCleanStringOperator_thenSuccess() {
List<String> list = Arrays.asList("john_1", "tom-3");
List<String> results = new ArrayList<>();
Observable<String> observable = Observable
.from(list)
.lift(toCleanString());
observable.subscribe(results::add);
assertThat(results, notNullValue());
assertThat(results, hasSize(2));
assertThat(results, hasItems("john1", "tom3"));
}
4. Трансформатор
Мы также можно создать наш оператор, реализовав интерфейс Transformer:
public class ToLength implements Transformer<String, Integer> {
public static ToLength toLength() {
return new ToLength();
}
private ToLength() {
super();
}
@Override
public Observable<Integer> call(Observable<String> source) {
return source.map(String::length);
}
}
Обратите внимание, что мы используем преобразователь toLength для преобразования нашего наблюдаемого объекта из String в его длину в Integer.
Нам понадобится оператор compose, чтобы использовать наш преобразователь:
observable.compose(toLength())...
Вот простой тест:
@Test
public void whenUseToLengthOperator_thenSuccess() {
List<String> list = Arrays.asList("john", "tom");
List<Integer> results = new ArrayList<>();
Observable<Integer> observable = Observable
.from(list)
.compose(toLength());
observable.subscribe(results::add);
assertThat(results, notNullValue());
assertThat(results, hasSize(2));
assertThat(results, hasItems(4, 3));
}
Подъем (оператор) работает с наблюдаемыми подписчиками, но компоновка (трансформатор) работает с наблюдаемыми. сам.
Когда мы создаем наш пользовательский оператор, мы должны выбрать Transformer, если мы хотим работать с наблюдаемым в целом, и выбрать Operator, если мы хотим работать с элементами, испускаемыми наблюдаемым
5. Пользовательский оператор как функция
Мы можем реализовать наш пользовательский оператор как функцию вместо публичного класса:
Operator<String, String> cleanStringFn = subscriber -> {
return new Subscriber<String>(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);
}
}
};
};
А вот простой тест:
List<String> 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"));
Аналогично для примера Transformer:
@Test
public void whenUseFunctionTransformer_thenSuccess() {
Transformer<String, Integer> toLengthFn = s -> s.map(String::length);
List<Integer> 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. Заключение ~ ~~ В этой статье мы показали, как писать операторы RxJava.
И, как всегда, полный исходный код можно найти на GitHub.
«