前言
RxJava不仅提供了大量的操作,例如map、flatMap(相关博客),还支持自定义操作符。
官方文档给出了自定义操作符的相关建议:
如果操作符是用于Observable发射的单独的数据项,则使用序列化操作符ObservableOperator。
如果你的操作符是用于变换Observable发射的整个数据序列,则使用变换操作符ObservableTransformer。
自定义序列化操作符
最近项目中有了这样一个需求:从后台获取了原始数据DataA,在前端加工处理后成DataB提交给后台。项目中大量地方使用了这个方法,刚开始是使用了一个Utils进行数据转换。但是我发现项目中的网络请求都是使用RxJava实现的。那么RxJava中有没有什么优雅的实现数据转换呢?我首先想到的是map操作符,但是每次使用map还要传入转换逻辑,真的很麻烦。而序列化操作符干好可以完美的实现我们的要求。接下来我们就通过一个简单的例子来看如何自定义序列化操作符。
假设存在一个这样的User的实例,我们要从中获取到它的name
class User {
private String name;
private List book;
}
这是个伪需求啊,我们完全可以使用map操作符实现这个功能:
map(new Function() {
@Override
public String apply(User user) throws Throwable {
return user.getName();
}
})
但这中方法每次都要写一遍转换逻辑,也就是return user.getName()。如果转换逻辑很复杂呢,如果我们不想关心转换过程,但业务中却大量需要呢?接下来就是轮到自定义操作符出场了。
首先,我们自定义一个ObservableOperator:
public class UserToName
implements ObservableOperator {
@Override
public Observer apply(Observer observer) {
return new Observer() {
private Disposable mDisposable;
@Override
public void onSubscribe(Disposable d) {
mDisposable = d;
observer.onSubscribe(d);
}
@Override
public void onNext(User o) {
if (!mDisposable.isDisposed()) {
observer.onNext(o.getName());
}
}
@Override
public void onError(Throwable e) {
if (!mDisposable.isDisposed()) {
observer.onNext(e);
}
}
@Override
public void onComplete() {
if (!mDisposable.isDisposed()) {
observer.onComplete();
}
}
};
}
}
接下来使用lift操作符搭配使用它:
User dostoyevsky = new User("陀思妥耶夫斯基", book1);
Observable.just(dostoyevsky)
.lift(new UserToName())
.subscribe(new Consumer() {
@Override
public void accept(String s) throws Throwable {
System.out.println(s);
}
});
>>>陀思妥耶夫斯基
业务逻辑处只要一行代码就可以实现变换操作。
UserToName这个类实现了ObservableOperator接口,你也可以重写UserToName的构造方法做一些初始化操作。
ObservableOperator的源码如下:
public interface ObservableOperator {
@NonNull
Observer super Upstream> apply(@NonNull Observer super Downstream> observer) throws Exception;
}
这段代码很简单,他做了一个将一个方法用于原始的Observer并返回一个新的Observer。用新的Observer监听原始的Observable。而left也会返回一个新的Observable,该Observable发送String类型的数据,用原始的Observer去订阅它。其中Downstream代表转换后的数据流,Upstream代表转换前的数据流。详细的原理参考从源码查看RxJava中的map和flatMap的用法与区别
自定义变换操作符
开篇就说到序列化操作符只能对Observable发射的单独的数据项进行处理,也就是这能对那个user进行操作,但对这个Observable却无能无力,例如我们想要打印上述user中所有的书名book。和上文中的一样,第一个想到的操作肯定是使用flatMap:
flatMap(new Function>() {
@Override
public ObservableSource> apply(User user) throws Throwable {
return Observable.fromIterable(user.getBook());
}
})
但是我偏不,我就要自己去实现。
image
首先实现一个ObservableTransformer
public class UserTransformer implements ObservableTransformer {
@Override
public ObservableSource apply(Observable upstream) {
return upstream.flatMap(new Function>() {
@Override
public ObservableSource apply(User user) throws Throwable {
return Observable.fromIterable(user.getBook());
}
});
}
}
接下来使用compose操作符实现它:
Observable.just(dostoyevsky)
.compose(new UserTransformer())
.subscribe(new Consumer() {
@Override
public void accept(String s) throws Throwable {
System.out.println(s);
}
});
我们看看ObservableTransformer的源码:
public interface ObservableTransformer {
@NonNull
ObservableSource apply(@NonNull Observable upstream);
}
什么鬼玩意儿哦!这东西的上游数据类型标注位置和ObservableOperator刚好相反!!
ObservableOperator
ObservableTransformer
这些我都不在乎,看看它干了什么?
将函数应用于上游原始的Observable并返回具有可选的不同元素类型的ObservableSource。其中Downstream就是用来指定不同元素的类型。
二者的区别
看完代码相信已经基本了解了它们的区别了:
前者作用于用于观察者层面,只对原始的被观察者发出的数据进行变换
后者作用于整个序列,对被观察进行了变化。
总结
完了。求大神带我
image