在 RxJava 中 doFinally 和 doAfterTerminate 这两个操作符很类似,都会在 Observable 的 onComplete 或 onError 调用之后进行调用。
使用了这两个操作符在 Observable 结束后,会调用 doFinally、doAfterTerminate 所提供的 Action。
这两个操作符虽然有一定的相似度,但他们依然有差别。并且两者在使用时,会存在调用的先后顺序。
doAfterTerminate
从 doAfterTerminate 操作符的源码来看
@CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) public final Observable<T> doAfterTerminate(Action onFinally) { ObjectHelper.requireNonNull(onFinally, "onFinally is null"); return doOnEach(Functions.emptyConsumer(), Functions.emptyConsumer(), Functions.EMPTY_ACTION, onFinally); }
它调用的是 doOnEach() 方法。
其实,doOnNext、doOnError、doOnComplete、doOnTerminate 等这些操作符也是调用 doOnEach() 方法。
doOnEach() 实际上调用的是 ObservableDoOnEach 类。( RxJavaPlugins.onAssembly 本身是一个 hook 方法,会返回一个 Observable 对象。)
doOnEach() 需要四个参数:onNext、onError、onComplete、onAfterTerminate。
doAfterTerminate 操作符的参数 onFinally 对应的是 onAfterTerminate。
@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 继承了 Observable 类,并实现了它的抽象方法 subscribeActual()。该方法是 Observable 和 Observer 连接的纽带。其中,source 代表了被观察者 Observable 本身,而 DoOnEachObserver 是实际的观察者。
@Override public void subscribeActual(Observer<? super T> t) { source.subscribe(new DoOnEachObserver<T>(t, onNext, onError, onComplete, onAfterTerminate)); }
从 DoOnEachObserver 中的 onError()、onComplete() 方法中可以看到 onAfterTerminate 是在 downstream.onError(t) 或者 downstream.onComplete() 之后,才执行 run()。这也符合我们最初对它的认识。
@Override public void onError(Throwable t) { if (done) { RxJavaPlugins.onError(t); return; } done = true; try { onError.accept(t); } catch (Throwable e) { Exceptions.throwIfFatal(e); t = new CompositeException(t, e); } downstream.onError(t); try { onAfterTerminate.run(); } catch (Throwable e) { Exceptions.throwIfFatal(e); RxJavaPlugins.onError(e); } } @Override public void onComplete() { if (done) { return; } try { onComplete.run(); } catch (Throwable e) { Exceptions.throwIfFatal(e); onError(e); return; } done = true; downstream.onComplete(); try { onAfterTerminate.run(); } catch (Throwable e) { Exceptions.throwIfFatal(e); RxJavaPlugins.onError(e); } }
doFinally
doFinally 是 RxJava 在 2.0.1 版本新增的操作符。
doFinally 除了拥有 doAfterTerminate 的特性之外,还会在下游(downstream)取消时被调用。这是 doFinally 和 doAfterTerminate 最大的区别。
同样,看一下 doFinally 的源码。它调用的是 ObservableDoFinally 类。
public final Observable<T> doFinally(Action onFinally) { ObjectHelper.requireNonNull(onFinally, "onFinally is null"); return RxJavaPlugins.onAssembly(new ObservableDoFinally<T>(this, onFinally)); }
在 ObservableDoFinally 类中,从 subscribeActual() 可以看出它的实际观察者是 DoFinallyObserver 类。其中,onFinally 是 doFinally 操作符所传递的参数。
@Override protected void subscribeActual(Observer<? super T> observer) { source.subscribe(new DoFinallyObserver<T>(observer, onFinally)); }
在 DoFinallyObserver 类中的 onError、onComplete、dispose 方法中都会调用 runFinally() 方法。而 runFinally() 执行的正是 onFinally 的 run()。
@Override public void onError(Throwable t) { downstream.onError(t); runFinally(); } @Override public void onComplete() { downstream.onComplete(); runFinally(); } @Override public void dispose() { upstream.dispose(); runFinally(); } ...... void runFinally() { if (compareAndSet(0, 1)) { try { onFinally.run(); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); RxJavaPlugins.onError(ex); } } }
所以,从源码可以得出在 doFinally 是在观察者执行完 onError、onComplete 或取消时执行的操作。
二者的顺序
doFinally 和 doAfterTerminate 都会在 onComplete 之后才执行,那么它们二者的顺序是如何呢?
不妨写一段代码测试一下:
Observable.just("Hello World") .doOnNext(s -> System.out.println("doOnNext:")) .doFinally(() -> System.out.println("doFinally:")) .doAfterTerminate(() -> System.out.println("doAfterTerminate:")) .subscribe( s -> System.out.println("onNext:" + s), throwable -> System.out.println("onError:"), () -> System.out.println("onComplete:"));
执行结果:
doOnNext: onNext:Hello World onComplete: doAfterTerminate: doFinally:
发现 doFinally 是在 doAfterTerminate 之后调用。
那么交换一下它们的顺序会如何呢?
Observable.just("Hello World") .doOnNext(s -> System.out.println("doOnNext:")) .doAfterTerminate(() -> System.out.println("doAfterTerminate:")) .doFinally(() -> System.out.println("doFinally:")) .subscribe( s -> System.out.println("onNext:" + s), throwable -> System.out.println("onError:"), () -> System.out.println("onComplete:"));
执行结果:
doOnNext: onNext:Hello World onComplete: doFinally: doAfterTerminate:
这一次,doFinally 先执行而 doAfterTerminate 后执行。
因为,它们都需要在 downstream.onComplete() 执行之后,才会执行。而 downstream 对应的下游是观察者。下流的数据流向跟上游的数据流向是相反的,从下向上的。所以,离观察者越近,就越先执行。这就是两段代码执行顺序不同的缘故。
最后,写一个极端一点的例子,先后调用 doFinally、doAfterTerminate、doFinally、doAfterTerminate:
Observable.just("Hello World") .doOnNext(s -> System.out.println("doOnNext:")) .doFinally(() -> System.out.println("doFinally1:")) .doAfterTerminate(() -> System.out.println("doAfterTerminate1:")) .doFinally(() -> System.out.println("doFinally2:")) .doAfterTerminate(() -> System.out.println("doAfterTerminate2:")) .subscribe( s -> System.out.println("onNext:" + s), throwable -> System.out.println("onError:"), () -> System.out.println("onComplete:"));
执行结果:
doOnNext: onNext:Hello World onComplete: doAfterTerminate2: doFinally2: doAfterTerminate1: doFinally1:
在 onComplete 调用之后,先打印了"doAfterTerminate2:",再打印"doFinally2:",然后打印"doAfterTerminate1:",最后打印"doFinally1:"。这正好符合刚才的分析。
总结
本文是对 doFinally 和 doAfterTerminate 两个操作符的总结。