这一篇主要是分享一下自定义操作符和几个常见的操作符。
自定义操作符的意义:在我看来学习自定义操作符的过程就是个检验你对Rxjava理解的过程。
下面我们来看一下Rxjava的简单使用场景,Rxjava+retrofit+okhttp
//定义接口api,这两个wangAndroid找的,感谢鸿洋大佬,随便看下就好,下面会分析使用。
public interface WangAndroidApi {
//总数据
@GET("project/tree/json")
Observable<ProjectBean> getProject();
//item数据
@GET("project/list/{pageIndex}/json")
Observable<ProjectItem> getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);
}
接下来我们需要两个javaBean,这里我就不占用篇幅展示了,给个截图。转换javaBean的工具或者方法大家随便百度搜索一下就有。
定义我们的网络工具类
public class HttpUtil {
public final static String BASE_URL = "https://www.wanandroid.com/";
/**
* 根据各种配置创建出Retrofit
*
* @return 返回创建好的Retrofit
*/
public static Retrofit getOnlineCookieRetrofit() {
// OKHttp客户端
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
// 各种参数配置
OkHttpClient okHttpClient = httpBuilder
.addNetworkInterceptor(new StethoInterceptor())
.readTimeout(10000, TimeUnit.SECONDS)
.connectTimeout(10000, TimeUnit.SECONDS)
.writeTimeout(10000, TimeUnit.SECONDS)
.build();
return new Retrofit.Builder().baseUrl(BASE_URL)
.client(okHttpClient)
// 添加一个json解析的工具
.addConverterFactory(GsonConverterFactory.create(new Gson()))
// 添加rxjava处理工具
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
}
布局非常简单,就是两个button,点击获取数据然后将数据显示下面textview里面。
篇幅不能弄太多,上面的东西其实不看也行。
api = HttpUtil.getOnlineCookieRetrofit().create(WangAndroidApi.class);
RxView.clicks(btn1)
.throttleFirst(2000,TimeUnit.MILLISECONDS)
//给下面的代码安排io线程
.observeOn(Schedulers.io())
//flatMap自己本身可以作为ObservableSource事件源往下传递
.flatMap(new Function<Object, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Object o) throws Exception {
return api.getProject();
}
})
.map(new Function<ProjectBean, ProjectBean>() {
@Override
public ProjectBean apply(ProjectBean bean) throws Exception {
return bean;
}
})
//给下面安排主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ProjectBean>() {
@Override
public void onSubscribe(Disposable d) {
//持有中断当前流的disposable
disposable = d;
}
@Override
public void onNext(ProjectBean projectBean) {
//拿到数据显示到textView上
textView.setText(projectBean.getData().toString());
}
@Override
public void onError(Throwable e) {
Log.v(TAG, e.toString());
}
@Override
public void onComplete() {
//数据发送完了
}
});
(我看的Rxbingding版本2.1.1确实是这样,同事的3.x版本没有报错,最新版本没有这个问题,写在这里可以加深理解。)
这里面为什么要使用flatMap和一个Map,是因为要在这里说明一下它们之间的一个不同点。
当我们使用RxView这样的操作符的时候传递下来的是一个没有实现ObservableSource的Observable,实际上在Rxjava中流传递Observable都是要实现了ObservableSource接口,如果你不实现这个接口,你怎么使用ObservableSource的实现方法subscribe将对象往上传递呢,所以这里用了一个flatMap操作符,它的返回对象实现了ObservableSource,之后map才能正常使用,它接收的是:ObservableSource《T》 source
它没有实现ObservableSource接口,而我们的map操作符要一个实现了ObservableSource接口的Observable,这是不行的,无法往下传递了。
这是一个正常调用代码,里面没有什么难点,直接看过去就行了。
下面我们要自定义一个RxView这样的操作符。
//我的MyView里面实现了一个操作符(函数),首先是静态直接使用,它需要返回一个Observable
public class MyRxView {
//这里是Object,不传递泛型了,<T>可以去掉 接收一个View
public static <T> Observable<T> Myclick(View view){
return new ViewClickObservable<>(view);
}
}
我们看一下ViewClickObservable的要求
1、它必须返回一个Observable,得实现Observable,在它的subscribeActual方法往下拆包,调用传递上来的对象调用它的onNext方法,因为它是源头,没有发射器,要自己调用。
2、点击效果必须可以中断,需要给下一层的对象赋值disposable
public class ViewClickObservable<T> extends Observable<T> {
//持有上一层传递过来的对象,这里的泛型其实都可以写成Object
private final View view;
//我们的事件
private static Object EVENT;
ViewClickObservable(View view){
this.view = view;
EVENT = view;
}
//实现下一层传递方法
@Override
protected void subscribeActual(Observer<? super T> observer) {
//根据操作符的原则,先包裹一层
// CreateEmitter<T> parent = new CreateEmitter<T>(observer);
//给下一层的disposable赋值
// observer.onSubscribe(parent);
MyListener myListener = new MyListener(view ,observer);
observer.onSubscribe(myListener);
//这个view就是上一层的对象,在这里不用往上传递了,上一层不是Observable,我自己就是第一层Observable
// 在Rxjava中是使用source.subscribe(当前对象) 往上传递,这里是源头,直接往下拆包
this.view.setOnClickListener(myListener);
}
//这里没有实现Observer,这个包裹没有自己的onNext等方法,因为不用再往上传递了,我自己就是事件源头了
//实际的Rxjava的Creae操作符是创建了一个发射器,并且自己实现了ObservableSource
//瞄了一眼Rxjava的RxView操作符,发现它也是这样做的,懒得去弄了。
static final class MyListener implements View.OnClickListener, Disposable {
private final View view;
private Observer observer;
private final AtomicBoolean isDisposable = new AtomicBoolean();
public MyListener(View view, Observer observer){
this.view = view;
this.observer = observer; //存一份下一层对象
}
@Override
public void onClick(View v) {
if (!isDisposed()) {
observer.onNext(EVENT);
}
}
//如何用户调用中断
@Override
public void dispose() {
//旧值替换新值,如果成功,说明旧值是false我执行之后变成true
if (isDisposable.compareAndSet(false ,true)) {
Log.v("ViewClickObservable","isDisposable:" + isDisposable);
//主线程,很好地中断
if (Looper.myLooper() == Looper.getMainLooper()) {
view.setOnClickListener(null);
} else { //通过handle切换之后再中断
// new Handler(Looper.getMainLooper()) {
// @Override
// public void handleMessage(@NonNull Message msg) {
// view.setOnClickListener(null);
// }
// };
//用一下Rxjava的.observeOn(AndroidSchedulers.mainThread()) 里面的handle
// HandlerScheduler.scheduleDirect 不是静态方法,类也不是public 且final修饰
//直接查看HandlerScheduler被谁实例化了找到下面调用路劲
AndroidSchedulers.mainThread().scheduleDirect(new Runnable() {
@Override
public void run() {
view.setOnClickListener(null);
}
});
}
}
}
@Override
public boolean isDisposed() {
return false;
}
}
}
写好之后我们直接将RxView替换成我们自己写的
MyRxView.Myclick(btn2)
.throttleFirst(2000, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.io())
//这里不能map,上面解释过了
.flatMap(new Function<Object, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Object o) throws Exception {
return api.getProject();
}
})
//上面传递下来了一个总数据javaBean,里面有很多个data,是一个集合
//fromIterable分发了集合里面所有的data的数量事件往下传递
.flatMap(new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {
@Override
public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
return Observable.fromIterable(projectBean.getData());
}
})
//每收到一个data也就是dataBean,获取它的ID,使用它的ID去获取子接口的数据
//同样的这里会接收到上面分发了集合的size的数量的,也是继续每接收一个往下传递一个
.flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
@Override
public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
return api.getProjectItem(1, dataBean.getId());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ProjectItem>() {
@Override
public void accept(ProjectItem projectItem) throws Exception {
//最终接收size数量的projectItem
textView.setText(projectItem.getData().toString());
}
});
操作符flatMap
.flatMap(new Function<Object, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Object o) throws Exception {
return api.getProject();
}
})
它实现了一个接口:
public interface Function<T, R> {
/**
* Apply some calculation to the input value and return some other value.
* @param t the input value
* @return the output value
* @throws Exception on error
*/
R apply(@NonNull T t) throws Exception;
}
接收Object,上面传递下来的流,然后返回ObservableSource,返回一个新的事件源或者流,新的流是: return api.getProject();
下面又再次调用flatMap
.flatMap(new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {
@Override
public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
return Observable.fromIterable(projectBean.getData());
}
})
这次返回的是 return Observable.fromIterable(projectBean.getData());,从方法名我们猜测难道是一个数组?进源码看看
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public static <T> Observable<T> fromIterable(Iterable<? extends T> source) {
ObjectHelper.requireNonNull(source, "source is null");
return RxJavaPlugins.onAssembly(new ObservableFromIterable<T>(source));
}
RxJavaPlugins.onAssembly是个hook,我们继续跟进:
final Iterable<? extends T> source;
public ObservableFromIterable(Iterable<? extends T> source) {
this.source = source;
}
跟紧我们的数据源,我们继续跟进source
@Override
public void subscribeActual(Observer<? super T> s) {
Iterator<? extends T> it;
try {
//持有了我们的数据源
it = source.iterator();
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
EmptyDisposable.error(e, s);
return;
}
boolean hasNext;
try {
hasNext = it.hasNext();
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
EmptyDisposable.error(e, s);
return;
}
if (!hasNext) {
EmptyDisposable.complete(s);
return;
}
//上面大多是代码健壮性判断,直接看这里
FromIterableDisposable<T> d = new FromIterableDisposable<T>(s, it);
s.onSubscribe(d);
if (!d.fusionMode) {
d.run();
}
}
通过 it = source.iterator(); 让it持有了我们的数据源,之后又运行了代码:
FromIterableDisposable d = new FromIterableDisposable(s, it);
它是一个静态内部类:
static final class FromIterableDisposable<T> extends BasicQueueDisposable<T> {
...
//do while循环,while (hasNext),当里面还有值的话就一直执行
do {
if (isDisposed()) {
return;
}
T v;
try {
//取出每一个值
v = ObjectHelper.requireNonNull(it.next(), "The iterator returned a null value");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
actual.onError(e);
return;
}
//往下传递
//通过前面三篇的学习应该知道actual是我们下一层的对象,每一个包裹里面的取值名字都一样
actual.onNext(v);
if (isDisposed()) {
return;
}
try {
hasNext = it.hasNext();
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
actual.onError(e);
return;
}
} while (hasNext);
if (!isDisposed()) {
actual.onComplete();
}
}
可以看到 final Iterator<? extends T> it;持有了我们的数据源,循环调用了回调方法将我们的数据分别发送给下游,回到我们的代码中。
接下来又再次使用了flatMap
.flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
@Override
public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
return api.getProjectItem(1,dataBean.getId());
}
}
从上面我们知道是循环持续发送了所有的数据,众多的itemBean,每一个都是一个新的流,那么下面肯定也是会不停地接收众多的流,接收每一个itenBean之后我们又转换发送了新的流:api.getProjectItem(1,dataBean.getId()); 我们通过接收到的数据获取它们的ID,来调用我们的获取子数据的api,然后继续往下传递。
.observeOn(AndroidSchedulers.mainThread())
切换成主线程
.subscribe
关联起观察者
new Consumer<ProjectItem>() {
@Override
public void accept(ProjectItem projectItem) throws Exception {
textView.setText(projectItem.getData().toString());
}
}
看一下被观察者实现了Consumer的接口代码
static final class ObserverOnNext<T> implements Consumer<T> {
final Observer<T> observer;
ObserverOnNext(Observer<T> observer) {
this.observer = observer;
}
@Override
public void accept(T v) throws Exception {
observer.onNext(v);
}
}
accept可以当做onNext,它会接收接收所有的流,数量就是上面Observable.fromIterable(projectBean.getData())中projectBean.getData的数组长度的数量
下面我们来看一下doOnNext操作符
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("aaa");
}
})
.doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, "accept: " + s);
}
})
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.d(TAG, "onNext: " + s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
doOnNext方法这里我啥都没做,就输出了上游传递下来的值,看源码:
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Observable<T> doOnNext(Consumer<? super T> onNext) {
//看这里
return doOnEach(onNext, Functions.emptyConsumer(), Functions.EMPTY_ACTION, Functions.EMPTY_ACTION);
}
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
private Observable<T> doOnEach(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Action onAfterTerminate) {
ObjectHelper.requireNonNull(onNext, "onNext is null");
ObjectHelper.requireNonNull(onError, "onError is null");
ObjectHelper.requireNonNull(onComplete, "onComplete is null");
ObjectHelper.requireNonNull(onAfterTerminate, "onAfterTerminate is null");
//直接看这里
return RxJavaPlugins.onAssembly(new ObservableDoOnEach<T>(this, onNext, onError, onComplete, onAfterTerminate));
}
在ObservableDoOnEach类里面
@Override
public void subscribeActual(Observer<? super T> t) {
//下游传递过来的对象,直接包裹一层传递给上游,我们知道等会发射器会调用onNext方法往下拆包
source.subscribe(new DoOnEachObserver<T>(t, onNext, onError, onComplete, onAfterTerminate));
}
直接看DoOnEachObserver的onNext方法
@Override
public void onNext(T t) {
if (done) {
return;
}
try {
//看这里
onNext.accept(t);
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
s.dispose();
onError(e);
return;
}
//下游的对象,往下拆包
actual.onNext(t);
}
//在这个类里面有这么一个成员,就是我们实现的doOnNext实现对象
final Consumer<? super T> onNext;
输出结果:
2021-02-28 15:30:50.132 6279-6279/com.example.xyztest D/MainActivity: accept: aaa
2021-02-28 15:30:50.132 6279-6279/com.example.xyztest D/MainActivity: onNext: aaa
doOnNext接收了上面传递下来的对象,然后继续往下传递啥都没改变,只是先自己拦截调用自己的accept方法输出对象。
从方法名来解释就是:在onNext方法调用前我先do一些自己想做的事情,不改变流的对象。
Rxjava的操作符非常多,但是其实是根据不同的类型创造的,我们懂得了Rxjava大概原理流程,如果要用到新的不认识的操作符怎么办?可以两步操作:
1、基本了解Rxjava的原理,直接看源码。
2、再百度一下辅助,基本能搞定了。
下面来一张终结图:
题外话:我的一个朋友说写博文不能篇幅太大,那些写得非常短的反而人气非常旺,但是一个技术点再怎么短小精悍也无法再压缩了啊,再小的话暂时对我来说没有什么意义,因为当前写的主要是一些常见基础技术的总结。