RxJava的Single、Completable以及Maybe

Maybe tomorrow.jpeg
Maybe tomorrow.jpeg

一般状况下,若是咱们想要使用 RxJava 首先会想到的是使用Observable,若是要考虑到Backpressure的状况,在 RxJava2.x 时代咱们会使用Flowable。除了Observable和Flowable以外,在 RxJava2.x 中还有三种类型的Observables:Single、Completable、Maybe。java

类型 描述
Observable 可以发射0或n个数据,并以成功或错误事件终止。
Flowable 可以发射0或n个数据,并以成功或错误事件终止。 支持Backpressure,能够控制数据源发射的速度。
Single 只发射单个数据或错误事件。
Completable 它历来不发射数据,只处理 onComplete 和 onError 事件。能够当作是Rx的Runnable。
Maybe 可以发射0或者1个数据,要么成功,要么失败。有点相似于Optional

从上面的表格能够看出,这五种被观察者类型中只有Flowable能支持Backpressure,若是有须要Backpressure的状况,仍是必需要使用Flowable。react

Single

从SingleEmitter的源码能够看出,Single 只有 onSuccess 和 onError 事件。express

/** * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */

package io.reactivex;

import io.reactivex.annotations.*;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Cancellable;

/** * Abstraction over an RxJava {@link SingleObserver} that allows associating * a resource with it. * <p> * All methods are safe to call from multiple threads. * <p> * Calling onSuccess or onError multiple times has no effect. * * @param <T> the value type to emit */
public interface SingleEmitter<T> {

    /** * Signal a success value. * @param t the value, not null */
    void onSuccess(@NonNull T t);

    /** * Signal an exception. * @param t the exception, not null */
    void onError(@NonNull Throwable t);

    /** * Sets a Disposable on this emitter; any previous Disposable * or Cancellation will be unsubscribed/cancelled. * @param s the disposable, null is allowed */
    void setDisposable(@Nullable Disposable s);

    /** * Sets a Cancellable on this emitter; any previous Disposable * or Cancellation will be unsubscribed/cancelled. * @param c the cancellable resource, null is allowed */
    void setCancellable(@Nullable Cancellable c);

    /** * Returns true if the downstream cancelled the sequence. * @return true if the downstream cancelled the sequence */
    boolean isDisposed();
}复制代码

其中,onSuccess()用于发射数据(在Observable/Flowable中使用onNext()来发射数据)。并且只能发射一个数据,后面即便再发射数据也不会作任何处理。apache

Single的SingleObserver中只有onSuccess、onError,并无onComplete。这是 Single 跟其余四种被观察者最大的区别。api

Single.create(new SingleOnSubscribe<String>() {

            @Override
            public void subscribe(@NonNull SingleEmitter<String> e) throws Exception {

                e.onSuccess("test");
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(@NonNull String s) throws Exception {
                System.out.println(s);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(@NonNull Throwable throwable) throws Exception {
                throwable.printStackTrace();
            }
        });复制代码

上面的代码,因为Observer中有两个Consumer,还能够进一步简化成网络

Single.create(new SingleOnSubscribe<String>() {

            @Override
            public void subscribe(@NonNull SingleEmitter<String> e) throws Exception {

                e.onSuccess("test");
            }
        }).subscribe(new BiConsumer<String, Throwable>() {
            @Override
            public void accept(String s, Throwable throwable) throws Exception {
                System.out.println(s);
            }
        });复制代码

Single 能够经过toXXX方法转换成Observable、Flowable、Completable以及Maybe。架构

Completable

Completable在建立后,不会发射任何数据。从CompletableEmitter的源码能够看到app

/** * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */

package io.reactivex;

import io.reactivex.annotations.*;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Cancellable;

/** * Abstraction over an RxJava {@link CompletableObserver} that allows associating * a resource with it. * <p> * All methods are safe to call from multiple threads. * <p> * Calling onComplete or onError multiple times has no effect. */
public interface CompletableEmitter {

    /** * Signal the completion. */
    void onComplete();

    /** * Signal an exception. * @param t the exception, not null */
    void onError(@NonNull Throwable t);

    /** * Sets a Disposable on this emitter; any previous Disposable * or Cancellation will be disposed/cancelled. * @param d the disposable, null is allowed */
    void setDisposable(@Nullable Disposable d);

    /** * Sets a Cancellable on this emitter; any previous Disposable * or Cancellation will be disposed/cancelled. * @param c the cancellable resource, null is allowed */
    void setCancellable(@Nullable Cancellable c);

    /** * Returns true if the downstream disposed the sequence. * @return true if the downstream disposed the sequence */
    boolean isDisposed();
}复制代码

Completable 只有 onComplete 和 onError 事件,同时 Completable 并无map、flatMap等操做符,它的操做符比起 Observable/Flowable 要少得多。less

咱们能够经过fromXXX操做符来建立一个Completable。这是一个Completable版本的Hello World。ide

Completable.fromAction(new Action() {
            @Override
            public void run() throws Exception {

                System.out.println("Hello World");
            }
        }).subscribe();复制代码

Completable 常常会结合andThen操做符

Completable.create(new CompletableOnSubscribe() {
            @Override
            public void subscribe(@NonNull CompletableEmitter emitter) throws Exception {

                try {
                    TimeUnit.SECONDS.sleep(1);
                    emitter.onComplete();
                } catch (InterruptedException e) {
                    emitter.onError(e);
                }
            }
        }).andThen(Observable.range(1, 10))
        .subscribe(new Consumer<Integer>() {
            @Override
            public void accept(@NonNull Integer integer) throws Exception {
                System.out.println(integer);
            }
        });复制代码

在这里emitter.onComplete()执行完以后,代表Completable已经彻底执行完毕,接下来是执行andThen里的操做。

打印结果以下:

1
2
3
4
5
6
7
8
9
10复制代码

在Completable中,andThen有多个重载的方法,正好对应了五种被观察者的类型。

Completable andThen(CompletableSource next) <T> Maybe<T> andThen(MaybeSource<T> next) <T> Observable<T> andThen(ObservableSource<T> next) <T> Flowable<T> andThen(Publisher<T> next) <T> Single<T> andThen(SingleSource<T> next)复制代码

Completable 也能够经过toXXX方法转换成Observable、Flowable、Single以及Maybe。

在网络操做中,若是遇到更新的状况,也就是Restful架构中的PUT操做,通常要么返回原先的对象要么只提示更新成功。下面两个接口使用了Retrofit,分别是用于获取短信验证码和更新用户信息,其中更新用户信息若是用PUT会更符合Restful的API。

/** * 获取短信验证码 * @param param * @return */
    @POST("v1/user-auth")
    Completable getVerificationCode(@Body VerificationCodeParam param);

    /** * 用户信息更新接口 * @param param * @return */
    @POST("v1/user-update")
    Completable update(@Body UpdateParam param);复制代码

在model类中大体会这样写。

/** * Created by Tony Shen on 2017/7/24. */

public class VerificationCodeModel extends HttpResponse {

    /** * 获取验证码 * @param activity * @param param * @return */
    public Completable getVerificationCode(AppCompatActivity activity, VerificationCodeParam param) {

        return apiService
                .getVerificationCode(param)
                .compose(RxJavaUtils.<VerificationCodeModel>completableToMain())
                .compose(RxLifecycle.bind(activity).<VerificationCodeModel>toLifecycleTransformer());
    }
}复制代码

特别要注意的是getVerificationCode返回的是Completable而不是Completable

获取验证码成功则给出相应地toast提示,失败能够作出相应地处理。

VerificationCodeModel model = new VerificationCodeModel();
model.getVerificationCode(RegisterActivity.this,param)
           .subscribe(new Action() {
                      @Override
                      public void run() throws Exception {
                              showShort(RegisterActivity.this,"发送验证码成功");
                      }
            },new RxException<Throwable>(){
                      @Override
                     public void accept(@NonNull Throwable throwable) throws Exception {
                              throwable.printStackTrace();
                              ......
                     }
            });复制代码

获取手机验证码.jpeg
获取手机验证码.jpeg

Maybe

Maybe 是 RxJava2.x 以后才有的新类型,能够当作是Single和Completable的结合。

Maybe建立以后,MaybeEmitter 和 SingleEmitter 同样并无onNext()方法,一样须要经过onSuccess()方法来发射数据。

Maybe.create(new MaybeOnSubscribe<String>() {

            @Override
            public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
                e.onSuccess("testA");
            }
        }).subscribe(new Consumer<String>() {

            @Override
            public void accept(@NonNull String s) throws Exception {

                System.out.println("s="+s);
            }
        });复制代码

打印出来的结果是

s=testA复制代码

Maybe也只能发射0或者1个数据,即便发射多个数据,后面发射的数据也不会处理。

Maybe.create(new MaybeOnSubscribe<String>() {

            @Override
            public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
                e.onSuccess("testA");
                e.onSuccess("testB");
            }
        }).subscribe(new Consumer<String>() {

            @Override
            public void accept(@NonNull String s) throws Exception {

                System.out.println("s="+s);
            }
        });复制代码

打印出来的结果仍然是

s=testA复制代码

跟第一次执行的结果是一致的。

若是MaybeEmitter先调用了onComplete(),即便后面再调用了onSuccess()也不会发射任何数据。

Maybe.create(new MaybeOnSubscribe<String>() {

            @Override
            public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
                e.onComplete();
                e.onSuccess("testA");
            }
        }).subscribe(new Consumer<String>() {

            @Override
            public void accept(@NonNull String s) throws Exception {

                System.out.println("s="+s);
            }
        });复制代码

此次就没有打印任何数据了。

咱们对上面的代码再作一下修改,在subscribe()中也加入onComplete(),看看打印出来的结果会是这样的?由于SingleObserver中是没有onComplete()方法。

Maybe.create(new MaybeOnSubscribe<String>() {

            @Override
            public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
                e.onComplete();
                e.onSuccess("testA");
            }
        }).subscribe(new Consumer<String>() {

            @Override
            public void accept(@NonNull String s) throws Exception {

                System.out.println("s=" + s);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(@NonNull Throwable throwable) throws Exception {

            }
        }, new Action() {
            @Override
            public void run() throws Exception {
                System.out.println("Maybe onComplete");
            }
        });复制代码

此次打印的结果是

Maybe onComplete复制代码

经过查看Maybe相关的源码

@CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public final Disposable subscribe(Consumer<? super T> onSuccess, Consumer<? super Throwable> onError, Action onComplete) {
        ObjectHelper.requireNonNull(onSuccess, "onSuccess is null");
        ObjectHelper.requireNonNull(onError, "onError is null");
        ObjectHelper.requireNonNull(onComplete, "onComplete is null");
        return subscribeWith(new MaybeCallbackObserver<T>(onSuccess, onError, onComplete));
    }复制代码

咱们能够获得,Maybe在没有数据发射时候subscribe会调用MaybeObserver的onComplete()。若是Maybe有数据发射或者调用了onError(),是不会再执行MaybeObserver的onComplete()。

咱们也能够将 Maybe 转换成Observable、Flowable、Single,只需相应地调用toObservable()、toFlowable()、toSingle()。

接下来咱们再来看看 Maybe 跟 Retrofit 是怎样结合使用的?
下面的网络请求,最初返回的类型是Flowable,可是这个网络请求并非一个连续事件流,咱们只会发起一次 Post 请求返回数据而且只收到一个事件。所以,能够考虑将 onComplete() 能够跟 onNext() 合并。在这里,尝试咱们将Flowable改为Maybe。

@POST("v1/contents")
    Maybe<ContentModel> loadContent(@Body ContentParam param);复制代码

在model类中,咱们大体会这样写。

public class ContentModel extends HttpResponse {

    public List<ContentItem> data;

    /** * 获取内容 * @param fragment * @param param * @param cacheKey * @return */
    public Maybe<ContentModel> getContent(Fragment fragment,ContentParam param,String cacheKey) {

        return apiService.loadContent(param)
                .compose(RxLifecycle.bind(fragment).<ContentModel>toLifecycleTransformer())
                .compose(RxJavaUtils.<ContentModel>maybeToMain())
                .compose(RxUtils.<ContentModel>toCacheTransformer(cacheKey,App.getInstance().cache));
    }

    ......
}复制代码

其中,maybeToMain()方法是用Kotlin编写的工具方法,这些工具方法由Kotlin来编写会显得比较简单和清晰,特别是lambda表达式更加直观。

@JvmStatic
    fun <T> maybeToMain(): MaybeTransformer<T, T> {

        return MaybeTransformer{
            upstream ->
            upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
        }
    }复制代码

最后是真正地使用model类,若是网络请求成功则将数据展现到recyclerview上,若是失败也会作出相应地处理。

model.getContent(this,param,cacheKey)
                .subscribe(new Consumer<ContentModel>() {
                    @Override
                    public void accept(@io.reactivex.annotations.NonNull ContentModel model) throws Exception {

                        adapter = new NewsAdapter(mContext, model);
                        recyclerview.setAdapter(adapter);
                        spinKitView.setVisibility(View.GONE);
                    }
                }, new RxException<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                        spinKitView.setVisibility(View.GONE);

                        ......
                    }
                });复制代码

获取内容的request.jpeg
获取内容的request.jpeg

获取内容的response.jpeg
获取内容的response.jpeg

总结

RxJava 有五种不一样类型的被观察者,合理地使用它们可以写出更简洁优雅的代码。这些被观察者在必定程度上也可以做一些相互转换。值得注意的是,只有Flowable是支持Backpressure的,其他四种都不支持。

相关文章
相关标签/搜索