RxJava2.0文章三 - Map和FlatMap操作符的用法

前言

上一节我们讲解了线程的调度,并且也写了一个登陆功能的示例代码,只是单独的写了一个登陆的,如果是新用户,需要先注册然后登陆,这个就属于嵌套的网络请求,在这一节的最后我会给大家写两种具体的实现方式。

这一节主要内容就是介绍下操作符Map和FlatMap的用法。

1. Map操作符


作用是把上游发送的每一个事件,都按照指定的方法去变化即可。如下图所示:


RxJava2.0文章三 - Map和FlatMap操作符的用法_第1张图片
map.png
由上图可知:

map中的方法的作用就是 把 圆形事件 转为 矩形事件,也就是说下游接收到的事件就是 矩形事件,示例代码如下:

/**
     * map中的方法作用:
     *         把圆形事件转为 矩形事件,也就是说下游接收的事件变为 矩形事件
     */
    public static void demo1(){
        Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).map(new Function() {
            @Override
            public String apply(Integer integer) throws Exception {
                return "This is result " + integer;
            }
        }).subscribe(new Consumer() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("TAG" , "s -> " + s) ;
            }
        });

    }

运行结果如下:

TAG: s -> This is result 1
TAG: s -> This is result 2
TAG: s -> This is result 3
结论

通过Map,可以把上游的事件转换为任意类型,可以是一个 Object,或者是一个集合。

2. FlatMap


FlatMap作用就是 把发送事件上游的 Observable 转换为 多个发送事件的 Observables,然后把他们发射的事件合并后放到一个单独的 Observable里。
这句话可以用如下图进行理解:


RxJava2.0文章三 - Map和FlatMap操作符的用法_第2张图片
flatMap.png

由上图可知,上游发射3个事件,分别是1、2、3,注意3个颜色。
flatMap作用是把上游的3个圆形事件分别转换为一个 发射矩形事件和 一个 发射三角形事件新的上游 Observable,如果不是很理解,看下我下边的分解图解:


RxJava2.0文章三 - Map和FlatMap操作符的用法_第3张图片
flatMap分解.png

由分解图片可知:
1>:上游每发射一个事件,flatMap都会创建一个新的水管,也就是说上游会创建3个水管;
2>:然后把3个水管的圆形事件 全部转换为 对应的三角事件和矩形事件,然后发射转换之后新的事件;
3>:下游接收到的就是这些新的水管发射过来的数据;

注意:

1>:flatMap不能保证事件的顺序,也就是说事件1、事件2、事件3顺序不一样;
2>:如果想要保证顺序,可以使用 concatMap;
flatMap示例代码如下:

     /**
     * flatMap中方法作用:
     *       将一个发射事件上游的Observable转换为多个发射事件的 Observable,
     *       然后把转换之后的多个事件合并后放到一个单独的 Observable里
     */
    public static void flatMap(){
        // 创建一个上游:Observable
        Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }

        /**
          * flatMap中把上游发射来的3个事件,转换为一个新的发射3个String事件的水管,
          * 为了看到flatMap是无效的,下边延迟10ms
         */
        }).flatMap(new Function>() {
            @Override
            public ObservableSource apply(Integer integer) throws Exception {
                final List list = new ArrayList() ;
                for (int i = 0 ; i < 3 ; i++){
                    list.add("I am value " + integer) ;
                }
                return Observable.fromIterable(list).delay(10 , TimeUnit.MILLISECONDS);
            }

        // 建立连接、创建一个下游:Observer
        }).subscribe(new Consumer() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("TAG", "s -> " + s);
            }
        });
    }

运行结果如下:

TAG: s -> I am value 1
TAG: s -> I am value 1
TAG: s -> I am value 1
TAG: s -> I am value 2
TAG: s -> I am value 2
TAG: s -> I am value 2
TAG: s -> I am value 3
TAG: s -> I am value 3
TAG: s -> I am value 3

concatMap与flatMap代码一样一样的,只是把 flatMap换为 concatMap即可,这样打印出来是保证顺序的。

3. 实践


针对于注册成功后然后登陆,有两种实现方式:

第一种:最常规的写法,也是最容易理解的,就是写两个方法,分别是注册和登陆即可;
    /**
     * 登录
     */
    public static void login(final Context context){

        Api api = RetrofitProvider.get().create(Api.class) ;
        api.login(new LoginRequest())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(LoginResponse value) {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG" , "登录失败") ;
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG" , "登录成功") ;
                    }
                });
    }


    /**
     * 注册
     */
    public static void register(final Context context){
        Api api = RetrofitProvider.get().create(Api.class) ;
        api.register(new RegisterRequest())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        
                    }

                    @Override
                    public void onNext(RegisterResponse value) {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG" , "注册失败") ;
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG" , "注册成功") ;
                    }
                });
    }
第二种:使用flatMap
/**
     * 使用flatMap实现嵌套的联网请求:
     *          先注册、后登录
     */
    public static void flatMapPritice(final Context context){
        final Api api = RetrofitProvider.get().create(Api.class) ;
        api.register(new RegisterRequest())                 // 发起注册的请求
                .subscribeOn(Schedulers.io())               // 在io线程中进行联网请求
                .observeOn(AndroidSchedulers.mainThread())  // 切换到主线程中处理 注册返回的结果
                .doOnNext(new Consumer() {
                    @Override
                    public void accept(RegisterResponse registerResponse) throws Exception {
                        // 根据请求注册接口的返回结果,然后做一些处理
                    }
                })
                .subscribeOn(Schedulers.io())           // 切换线程到主线程中 发起登录请求
                .flatMap(new Function>() {
                    @Override
                    public ObservableSource apply(RegisterResponse registerResponse) throws Exception {
                        return api.login(new LoginRequest());
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())  // 切换线程到主线程 处理登录返回的结果
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(LoginResponse value) {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG" , "登录失败") ;
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG" , "登录成功") ;
                    }
                });

        }

以上就是 flatMap的用法,注释写的比较清晰。
可以看出,切换线程相对来说还是比较简单的。

你可能感兴趣的:(RxJava2.0文章三 - Map和FlatMap操作符的用法)