RxJava2 中 doFinally 和 doAfterTerminate 的比较

本文深入探讨了RxJava中的doFinally和doAfterTerminate操作符,详细解释了它们之间的区别与联系,特别是在执行顺序上的差异,以及与观察者下游的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

640?wx_fmt=jpeg

在 RxJava 中 doFinally 和 doAfterTerminate 这两个操作符很类似,都会在 Observable 的 onComplete 或 onError 调用之后进行调用。

使用了这两个操作符在 Observable 结束后,会调用 doFinally、doAfterTerminate 所提供的 Action。

这两个操作符虽然有一定的相似度,但他们依然有差别。并且两者在使用时,会存在调用的先后顺序。

doAfterTerminate

从 doAfterTerminate 操作符的源码来看

  1.    @CheckReturnValue

  2.    @SchedulerSupport(SchedulerSupport.NONE)

  3.    public final Observable<T> doAfterTerminate(Action onFinally) {

  4.        ObjectHelper.requireNonNull(onFinally, "onFinally is null");

  5.        return doOnEach(Functions.emptyConsumer(), Functions.emptyConsumer(), Functions.EMPTY_ACTION, onFinally);

  6.    }

它调用的是 doOnEach() 方法。

其实,doOnNext、doOnError、doOnComplete、doOnTerminate 等这些操作符也是调用 doOnEach() 方法。

doOnEach() 实际上调用的是 ObservableDoOnEach 类。( RxJavaPlugins.onAssembly 本身是一个 hook 方法,会返回一个 Observable 对象。)

doOnEach() 需要四个参数:onNext、onError、onComplete、onAfterTerminate。doAfterTerminate 操作符的参数 onFinally 对应的是 onAfterTerminate。

  1.    @CheckReturnValue

  2.    @SchedulerSupport(SchedulerSupport.NONE)

  3.    private Observable<T> doOnEach(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Action onAfterTerminate) {

  4.        ObjectHelper.requireNonNull(onNext, "onNext is null");

  5.        ObjectHelper.requireNonNull(onError, "onError is null");

  6.        ObjectHelper.requireNonNull(onComplete, "onComplete is null");

  7.        ObjectHelper.requireNonNull(onAfterTerminate, "onAfterTerminate is null");

  8.        return RxJavaPlugins.onAssembly(new ObservableDoOnEach<T>(this, onNext, onError, onComplete, onAfterTerminate));

  9.    }

ObservableDoOnEach 继承了 Observable 类,并实现了它的抽象方法 subscribeActual()。该方法是 Observable 和 Observer 连接的纽带。其中,source 代表了被观察者 Observable 本身,而 DoOnEachObserver 是实际的观察者。

  1.    @Override

  2.    public void subscribeActual(Observer<? super T> t) {

  3.        source.subscribe(new DoOnEachObserver<T>(t, onNext, onError, onComplete, onAfterTerminate));

  4.    }

从 DoOnEachObserver 中的 onError()、onComplete() 方法中可以看到 onAfterTerminate 是在 downstream.onError(t) 或者 downstream.onComplete() 之后,才执行 run()。这也符合我们最初对它的认识。

  1.        @Override

  2.        public void onError(Throwable t) {

  3.            if (done) {

  4.                RxJavaPlugins.onError(t);

  5.                return;

  6.            }

  7.            done = true;

  8.            try {

  9.                onError.accept(t);

  10.            } catch (Throwable e) {

  11.                Exceptions.throwIfFatal(e);

  12.                t = new CompositeException(t, e);

  13.            }

  14.            downstream.onError(t);


  15.            try {

  16.                onAfterTerminate.run();

  17.            } catch (Throwable e) {

  18.                Exceptions.throwIfFatal(e);

  19.                RxJavaPlugins.onError(e);

  20.            }

  21.        }


  22.        @Override

  23.        public void onComplete() {

  24.            if (done) {

  25.                return;

  26.            }

  27.            try {

  28.                onComplete.run();

  29.            } catch (Throwable e) {

  30.                Exceptions.throwIfFatal(e);

  31.                onError(e);

  32.                return;

  33.            }


  34.            done = true;

  35.            downstream.onComplete();


  36.            try {

  37.                onAfterTerminate.run();

  38.            } catch (Throwable e) {

  39.                Exceptions.throwIfFatal(e);

  40.                RxJavaPlugins.onError(e);

  41.            }

  42.        }

doFinally

doFinally 是 RxJava 在 2.0.1 版本新增的操作符。

doFinally 除了拥有 doAfterTerminate 的特性之外,还会在下游(downstream)取消时被调用。这是 doFinally 和 doAfterTerminate 最大的区别。

同样,看一下 doFinally 的源码。它调用的是 ObservableDoFinally 类。

  1.    public final Observable<T> doFinally(Action onFinally) {

  2.        ObjectHelper.requireNonNull(onFinally, "onFinally is null");

  3.        return RxJavaPlugins.onAssembly(new ObservableDoFinally<T>(this, onFinally));

  4.    }

在 ObservableDoFinally 类中,从 subscribeActual() 可以看出它的实际观察者是 DoFinallyObserver 类。其中,onFinally 是 doFinally 操作符所传递的参数。

  1.    @Override

  2.    protected void subscribeActual(Observer<? super T> observer) {

  3.        source.subscribe(new DoFinallyObserver<T>(observer, onFinally));

  4.    }

在 DoFinallyObserver 类中的 onError、onComplete、dispose 方法中都会调用 runFinally() 方法。而 runFinally() 执行的正是 onFinally 的 run()。

  1.        @Override

  2.        public void onError(Throwable t) {

  3.            downstream.onError(t);

  4.            runFinally();

  5.        }


  6.        @Override

  7.        public void onComplete() {

  8.            downstream.onComplete();

  9.            runFinally();

  10.        }


  11.        @Override

  12.        public void dispose() {

  13.            upstream.dispose();

  14.            runFinally();

  15.        }


  16.        ......


  17.        void runFinally() {

  18.            if (compareAndSet(0, 1)) {

  19.                try {

  20.                    onFinally.run();

  21.                } catch (Throwable ex) {

  22.                    Exceptions.throwIfFatal(ex);

  23.                    RxJavaPlugins.onError(ex);

  24.                }

  25.            }

  26.        }

所以,从源码可以得出在 doFinally 是在观察者执行完 onError、onComplete 或取消时执行的操作。

二者的顺序

doFinally 和 doAfterTerminate 都会在 onComplete 之后才执行,那么它们二者的顺序是如何呢?

不妨写一段代码测试一下:

  1.        Observable.just("Hello World")

  2.                .doOnNext(s -> System.out.println("doOnNext:"))

  3.                .doFinally(() -> System.out.println("doFinally:"))

  4.                .doAfterTerminate(() -> System.out.println("doAfterTerminate:"))

  5.                .subscribe(

  6.                        s -> System.out.println("onNext:" + s),

  7.                        throwable -> System.out.println("onError:"),

  8.                        () -> System.out.println("onComplete:"));

执行结果:

  1. doOnNext

  2. onNextHello World

  3. onComplete

  4. doAfterTerminate

  5. doFinally

发现 doFinally 是在 doAfterTerminate 之后调用。

那么交换一下它们的顺序会如何呢?

  1.        Observable.just("Hello World")

  2.                .doOnNext(s -> System.out.println("doOnNext:"))

  3.                .doAfterTerminate(() -> System.out.println("doAfterTerminate:"))

  4.                .doFinally(() -> System.out.println("doFinally:"))

  5.                .subscribe(

  6.                        s -> System.out.println("onNext:" + s),

  7.                        throwable -> System.out.println("onError:"),

  8.                        () -> System.out.println("onComplete:"));

执行结果:

  1. doOnNext

  2. onNextHello World

  3. onComplete

  4. doFinally

  5. doAfterTerminate

这一次,doFinally 先执行而 doAfterTerminate 后执行。

因为,它们都需要在 downstream.onComplete() 执行之后,才会执行。而 downstream 对应的下游是观察者。下流的数据流向跟上游的数据流向是相反的,从下向上的。所以,离观察者越近,就越先执行。这就是两段代码执行顺序不同的缘故。

最后,写一个极端一点的例子,先后调用 doFinally、doAfterTerminate、doFinally、doAfterTerminate:

  1.        Observable.just("Hello World")

  2.                .doOnNext(s -> System.out.println("doOnNext:"))

  3.                .doFinally(() -> System.out.println("doFinally1:"))

  4.                .doAfterTerminate(() -> System.out.println("doAfterTerminate1:"))

  5.                .doFinally(() -> System.out.println("doFinally2:"))

  6.                .doAfterTerminate(() -> System.out.println("doAfterTerminate2:"))

  7.                .subscribe(

  8.                        s -> System.out.println("onNext:" + s),

  9.                        throwable -> System.out.println("onError:"),

  10.                        () -> System.out.println("onComplete:"));

执行结果:

  1. doOnNext

  2. onNextHello World

  3. onComplete

  4. doAfterTerminate2

  5. doFinally2

  6. doAfterTerminate1

  7. doFinally1

在 onComplete 调用之后,先打印了"doAfterTerminate2:",再打印"doFinally2:",然后打印"doAfterTerminate1:",最后打印"doFinally1:"。这正好符合刚才的分析。

总结

本文是对 doFinally 和 doAfterTerminate 两个操作符的总结。也是对《RxJava 2.x 实战》一书中,第二章第一节最后一部分内容do操作符的补充。

只有了解源码,才能更踏实地去写我们的程序。


关注【Java与Android技术栈】

更多精彩内容请关注扫码

640?wx_fmt=jpeg


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值