美文网首页Android-RxJavaAndroid-Rxjava&retrofit&daggerAndroid进阶
RxJava2.0文章三 - Map和FlatMap操作符的用法

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

作者: 世道无情 | 来源:发表于2018-04-29 20:15 被阅读22次

    前言

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

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

    1. Map操作符


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


    map.png
    由上图可知:

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

    /**
         * map中的方法作用:
         *         把圆形事件转为 矩形事件,也就是说下游接收的事件变为 矩形事件
         */
        public static void demo1(){
            Observable.create(new ObservableOnSubscribe<Integer>() {
                @Override
                public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                    emitter.onNext(1);
                    emitter.onNext(2);
                    emitter.onNext(3);
                }
            }).map(new Function<Integer, String>() {
                @Override
                public String apply(Integer integer) throws Exception {
                    return "This is result " + integer;
                }
            }).subscribe(new Consumer<String>() {
                @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里。
    这句话可以用如下图进行理解:


    flatMap.png

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


    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<Integer>() {
                @Override
                public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                    emitter.onNext(1);
                    emitter.onNext(2);
                    emitter.onNext(3);
                }
    
            /**
              * flatMap中把上游发射来的3个事件,转换为一个新的发射3个String事件的水管,
              * 为了看到flatMap是无效的,下边延迟10ms
             */
            }).flatMap(new Function<Integer, ObservableSource<String>>() {
                @Override
                public ObservableSource<String> apply(Integer integer) throws Exception {
                    final List<String> list = new ArrayList<String>() ;
                    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<String>() {
                @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<LoginResponse>() {
                        @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<RegisterResponse>() {
                        @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<RegisterResponse>() {
                        @Override
                        public void accept(RegisterResponse registerResponse) throws Exception {
                            // 根据请求注册接口的返回结果,然后做一些处理
                        }
                    })
                    .subscribeOn(Schedulers.io())           // 切换线程到主线程中 发起登录请求
                    .flatMap(new Function<RegisterResponse, ObservableSource<LoginResponse>>() {
                        @Override
                        public ObservableSource<LoginResponse> apply(RegisterResponse registerResponse) throws Exception {
                            return api.login(new LoginRequest());
                        }
                    })
                    .observeOn(AndroidSchedulers.mainThread())  // 切换线程到主线程 处理登录返回的结果
                    .subscribe(new Observer<LoginResponse>() {
                        @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操作符的用法

        本文链接:https://www.haomeiwen.com/subject/ayaplftx.html