RxJava学习 - 13. Transformers and Custom Operators
可以使用compose()和lift()实现自己的operators。Observable和Flowable都有这两个方法。
Transformers
有时候,可能想重新使用Observable或者Flowable链的某个片段,可以使用某种方法,把这些operators组合成新的operators。
ObservableTransformer和FlowableTransformer提供了重新使用代码的能力。
ObservableTransformer
以前有个例子,使用collect()把Observable转成Single<ImmutableList>。看下面的例子:
import com.google.common.collect.ImmutableList;
import io.reactivex.Observable;
public class Launcher {
public static void main(String[] args) {
Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
.collect(ImmutableList::builder, ImmutableList.Builder::add)
.map(ImmutableList.Builder::build)
.subscribe(System.out::println);
Observable.range(1, 15)
.collect(ImmutableList::builder, ImmutableList.Builder::add)
.map(ImmutableList.Builder::build)
.subscribe(System.out::println);
}
}
下面的代码出现了两次:
collect(ImmutableList::builder, ImmutableList.Builder::add)
.map(ImmutableList.Builder::build)
我们可以想办法把他们组合成新的operator。对于目标Observable,你可以实现ObservableTransformer<T, R>。这个类有一个apply()方法,接受一个Observable,返回一个Observable。在你的实现里,你可以返回一个Observable链,把任何operators加给上游,然后返回Observable。
对我们的例子,要把Observable转换成Observable<ImmutableList>。我们包装一个ObservableTransformer<T, ImmutableList>:
public static <T> ObservableTransformer<T, ImmutableList<T>> toImmutableList() {
return new ObservableTransformer<T, ImmutableList<T>>() {
@Override
public ObservableSource<ImmutableList<T>> apply(Observable<T> upstream) {
return upstream.collect(ImmutableList::<T>builder, ImmutableList.Builder::add)
.map(ImmutableList.Builder::build)
.toObservable(); // must turn Single into Observable
}
};
}
因为collect()返回一个Single,我们调用toObservable()(因为ObservableTransformer期待一个Observable,而不是Single)。
ObservableTransformer只有一个抽象方法,所以可以使用lambda:
public static <T> ObservableTransformer<T, ImmutableList<T>> toImmutableList() {
return upstream -> upstream.collect(ImmutableList::<T>builder, ImmutableList.Builder::add)
.map(ImmutableList.Builder::build)
.toObservable(); // must turn Single into Observable
}
想在一个Observable链内调用Transformer,可以使用compose()方法。它接受一个ObservableTransformer<T, R>,返回转换后的Observable:
import com.google.common.collect.ImmutableList;
import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
public class Launcher {
public static void main(String[] args) {
Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
.compose(toImmutableList())
.subscribe(System.out::println);
Observable.range(1, 10)
.compose(toImmutableList())
.subscribe(System.out::println);
}
public static <T> ObservableTransformer<T, ImmutableList<T>> toImmutableList() {
return upstream -> upstream.collect(ImmutableList::<T>builder, ImmutableList.Builder::add)
.map(ImmutableList.Builder::build)
.toObservable(); // must turn Single into Observable
}
}
你也可以为特定的emission类型和接受的参数增加Transformers。例如,增加一个joinToString(),它接受一个分隔符,用来级联字符串:
import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
public class Launcher {
public static void main(String[] args) {
Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
.compose(joinToString("/"))
.subscribe(System.out::println);
}
public static ObservableTransformer<String, String> joinToString(String separator) {
return upstream -> upstream
.collect(StringBuilder::new, (b,s) -> {
if (b.length() == 0)
b.append(s);
else
b.append(separator).append(s);
})
.map(StringBuilder::toString)
.toObservable();
}
}
FlowableTransformer
当你实现ObservableTransformer的时候,也许觉得增加FlowableTransformer会更好。这样,你的operator可用于Observables,也可用于Flowables。
FlowableTransformer和ObservableTransformer差别不大。当然,和Flowables组合时,它支持背压:
import com.google.common.collect.ImmutableList;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
public class Launcher {
public static void main(String[] args) {
Flowable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
.compose(toImmutableList())
.subscribe(System.out::println);
Flowable.range(1, 10)
.compose(toImmutableList())
.subscribe(System.out::println);
}
public static <T> FlowableTransformer<T, ImmutableList<T>> toImmutableList() {
return upstream -> upstream.collect(ImmutableList::<T>builder, ImmutableList.Builder::add)
.map(ImmutableList.Builder::build)
.toFlowable(); // must turn Single into Observable
}
}
Avoiding shared state with Transformers
比如,你想增加一个ObservableTransformer<T, IndexedValue>,它把每个emission和一个从0开始的连续索引配对。首先,你增加一个IndexedValue类:
static final class IndexedValue<T> {
final int index;
final T value;
IndexedValue(int index, T value) {
this.index = index;
this.value = value;
}
@Override
public String toString() {
return index + " - " + value;
}
}
然后,你增加一个ObservableTransformer<T, IndexedValue>,使用一个AtomicInteger做索引:
static <T> ObservableTransformer<T,IndexedValue<T>> withIndex() {
final AtomicInteger indexer = new AtomicInteger(-1);
return upstream -> upstream.map(v -> new IndexedValue<T>(indexer.incrementAndGet(), v));
}
看出问题了吗?让我们运行下面的程序。仔细看输出:
import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
import java.util.concurrent.atomic.AtomicInteger;
public class Launcher {
public static void main(String[] args) {
Observable<IndexedValue<String>> indexedStrings =
Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
.compose(withIndex());
indexedStrings.subscribe(v -> System.out.println("Subscriber 1: " + v));
indexedStrings.subscribe(v -> System.out.println("Subscriber 2: " + v));
}
static <T> ObservableTransformer<T,IndexedValue<T>> withIndex() {
final AtomicInteger indexer = new AtomicInteger(-1);
return upstream -> upstream.map(v -> new IndexedValue<T>(indexer.incrementAndGet(), v));
}
static final class IndexedValue<T> {
final int index;
final T value;
IndexedValue(int index, T value) {
this.index = index;
this.value = value;
}
@Override
public String toString() {
return index + " - " + value;
}
}
}
输出是
Subscriber 1: 0 - Alpha
Subscriber 1: 1 - Beta
Subscriber 1: 2 - Gamma
Subscriber 1: 3 - Delta
Subscriber 1: 4 - Epsilon
Subscriber 2: 5 - Alpha
Subscriber 2: 6 - Beta
Subscriber 2: 7 - Gamma
Subscriber 2: 8 - Delta
Subscriber 2: 9 - Epsilon
注意,AtomicInteger的一个实例被两个订阅共享了。
可以为每个订阅增加一个资源(比如AtomicInteger),包装在Observable.defer()内:
static <T> ObservableTransformer<T,IndexedValue<T>> withIndex() {
return upstream -> Observable.defer(() -> {
AtomicInteger indexer = new AtomicInteger(-1);
return upstream.map(v -> new IndexedValue<T>(indexer.incrementAndGet(), v));
});
}
对于这个例子,也可以使用Observable.zip()或者zipWith(),解决我们的问题:
static <T> ObservableTransformer<T,IndexedValue<T>> withIndex() {
return upstream ->
Observable.zip(upstream,
Observable.range(0,Integer.MAX_VALUE),
(v,i) -> new IndexedValue<T>(i, v)
);
}
Operators
理想的情况下,你很少需要从头开始通过实现ObservableOperator和FlowableOperator构造自己的operator。ObservableTransformer和FlowableTransformer可以满足大多数需求。
可有时候,你发现不得不做些现有的operators不能做或者不容易做的事情。排除了任何选项,你可能不得不增加一个operator,在上游和下游之间操纵每个onNext()、onComplete()和onError()事件。
在你增加自己的operator之前,要先试试compose()。如果失败了,推荐你在StackOverflow提问题。
实在不行,再构造自己的operator。
Implementing an ObservableOperator
实现自己的ObservableOperator(或者FlowableTransformer)要做更多的工作。不组合现有的operators,你需要拦截onNext()、onComplete()、onError()和onSubscribe(),实现自己的Observer。该Observer把onNext()、onComplete()和onError()事件传给下游Observer。
比如,你要增加doOnEmpty() operator,当onComplete()被调用的时候,它会执行一个Action。要增加自己的ObservableOperator<Downstream, Upstream>,需要实现它的apply()方法。它接受一个Observer,返回一个Observer。然后,你可以通过调用lift(),使用这个ObservableOperator:
import io.reactivex.Observable;
import io.reactivex.ObservableOperator;
import io.reactivex.Observer;
import io.reactivex.functions.Action;
import io.reactivex.observers.DisposableObserver;
public class Launcher {
public static void main(String[] args) {
Observable.range(1, 5)
.lift(doOnEmpty(() -> System.out.println("Operation 1 Empty!")))
.subscribe(v -> System.out.println("Operation 1: " + v));
Observable.<Integer>empty()
.lift(doOnEmpty(() -> System.out.println("Operation 2 Empty!")))
.subscribe(v -> System.out.println("Operation 2: " + v));
}
public static <T> ObservableOperator<T, T> doOnEmpty(Action action) {
return new ObservableOperator<T, T>() {
@Override
public Observer<? super T> apply(Observer<? super T> observer) throws Exception {
return new DisposableObserver<T>() {
boolean isEmpty = true;
@Override
public void onNext(T value) {
isEmpty = false;
observer.onNext(value);
}
@Override
public void onError(Throwable t) {
observer.onError(t);
}
@Override
public void onComplete() {
if (isEmpty) {
try {
action.run();
} catch (Exception e) {
onError(e);
return;
}
}
observer.onComplete();
}
};
}
};
}
}
就像Transformers一样,当增加自己的operators的时候,不要在订阅之间共享状态。
还有,onNext()、onComplete()和onError()调用是可以按需要操纵和混合的。比如,toList()不会把收到的每个onNext()都传给下游。它会在内部列表中收集这些emissions。当上游调用了onComplete(),它就调用下游的onNext(),把列表传给下游,然后调用onComplete()。现在,我们实现自己的myToList(),来理解toList()如何工作:
import io.reactivex.Observable;
import io.reactivex.ObservableOperator;
import io.reactivex.observers.DisposableObserver;
import java.util.ArrayList;
import java.util.List;
public class Launcher {
public static void main(String[] args) {
Observable.range(1, 5)
.lift(myToList())
.subscribe(v -> System.out.println("Operation 1: " + v));
Observable.<Integer>empty()
.lift(myToList())
.subscribe(v -> System.out.println("Operation 2: " + v));
}
public static <T> ObservableOperator<List<T>,T> myToList() {
return observer -> new DisposableObserver<T>() {
ArrayList<T> list = new ArrayList<>();
@Override
public void onNext(T value) {
//add to List, but don't pass anything downstream
list.add(value);
}
@Override
public void onError(Throwable t) {
observer.onError(t);
}
@Override
public void onComplete() {
observer.onNext(list); //push List downstream
observer.onComplete();
}
};
}
}
Custom Transformers and operators for Singles, Maybes, and Completables
当你想增加一个Observable或者Flowable operator来产生Single,你可能发现是很容易的(使用SingleTransformer或者SingleOperator)。对Maybe(使用MaybeTransformer或者MaybeOperator)和Completable(CompletableTransformer或者CompletableOperator)也是如此。
下面是SingleTransformer的例子,接受Single<Collection>映射到一个不可变的集合:
import io.reactivex.Observable;
import io.reactivex.SingleTransformer;
import java.util.Collection;
import java.util.Collections;
public class Launcher {
public static void main(String[] args) {
Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
.toList()
.compose(toUnmodifiable())
.subscribe(System.out::println);
}
public static <T> SingleTransformer<Collection<T>, Collection<T>> toUnmodifiable() {
return singleObserver -> singleObserver.map(Collections::unmodifiableCollection);
}
}