RxJava(八)concat 符操作处理多数据源

15 篇文章 41 订阅

RxJava 系列文章目录导读:

一、RxJava create 操作符的用法和源码分析
二、RxJava map 操作符用法详解
三、RxJava flatMap 操作符用法详解
四、RxJava concatMap 操作符用法详解
五、RxJava onErrorResumeNext 操作符实现 app 与服务器间 token 机制
六、RxJava retryWhen 操作符实现错误重试机制
七、RxJava 使用 debounce 操作符优化 app 搜索功能
八、RxJava concat 操作处理多数据源
九、RxJava zip 操作符在 Android 中的实际使用场景
十、RxJava switchIfEmpty 操作符实现 Android 检查本地缓存逻辑判断
十一、RxJava defer 操作符实现代码支持链式调用
十二、combineLatest 操作符的高级使用
十三、RxJava 导致 Fragment Activity 内存泄漏问题
十四、interval、takeWhile 操作符实现获取验证码功能
十五、RxJava 线程的自由切换


一、concat 操作符概述

从 concatMap 操作我们知道,concat 操作符肯定也是有序的,而 concat 操作符是接收若干个 Observables,发射数据是有序的,不会交叉。

下面看看官方文档和流程图的说明:

Returns an Observable that emits the items emitted by three Observables, 
one after the other, without interleaving them.

在这里插入图片描述

二、使用示例

示例一

下面使用concat 操作符来实现个多数据源的例子,比如一个商品详情需要展示商品的信息、艺术家信息、与该商品类似的商品,可能需要访问三个接口。这个时候就可以使用concat 操作符。

卖家信息

    private Observable<Object> sellerInfo = Observable.create(new Observable.OnSubscribe<Object>() {
        @Override
        public void call(Subscriber<? super Object> subscriber) {
            Seller d = goodsApi.getSeller();
            if (d != null) {
                subscriber.onNext(d);
            }
            subscriber.onCompleted();
        }
    }).subscribeOn(Schedulers.io());

商品信息

    private Observable<Object> goodsInfo = Observable.create(new Observable.OnSubscribe<Object>() {
        @Override
        public void call(Subscriber<? super Object> subscriber) {
            Goods d = goodsApi.getGoodInfo();
            if (d != null) {
                subscriber.onNext(d);
            }
            subscriber.onCompleted();
        }
    }).subscribeOn(Schedulers.io());



类似作品推荐

    private Observable<Object> relateGoods = Observable.create(new Observable.OnSubscribe<Object>() {
        @Override
        public void call(Subscriber<? super Object> subscriber) {
            List<Goods> d = goodsApi.getRelateGoods();
            if (d != null) {
                subscriber.onNext(d);
            }
            subscriber.onCompleted();
        }
    }).subscribeOn(Schedulers.io());

Observable.concat(sellerInfo, goodsInfo, relateGoods)
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Action1<Object>() {
                            @Override
                            public void call(Object s) {
                                printLog(tvLogs, "Getting data from ", s);
                                //push data to ui
                            }
                        }, new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                throwable.printStackTrace();
                                printLog(tvLogs, "Error: ", throwable.getMessage());
                            }
                        });

为什么泛型去设置成Object呢,因为Observable.concat只接受相同泛型的参数。

也许会有人问获取商品信息的时候没办法传递参数啊(比如商品ID), 在外面包一层方法即可,方法参数为goodID。

示例二

使用 concat 操作符对缓存进行检查,如:内存缓存、本地缓存、网络,那一层有数据立即返回。

使用一个数组来表示三个数据源:

String data[] = {null, null, "network"};
//String data[] = {null, "disk","network"};
//String data[] = {"memory", null,"network"};
//String data[] = {"memory", "disk",null};
//String data[] = {"memory", "disk","network"};

内存缓存

  private Observable<String> memorySource = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            String d = data[0];
            printLog(tvLogs, "", "----start check memory data. value is null? " + (d == null));
            if (d != null) {
                subscriber.onNext(d);
            }
            subscriber.onCompleted();
        }
    });

本地缓存


    private Observable<String> diskSource = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            String d = data[1];
            printLog(tvLogs, "", "----start check disk data. value is null? " + (d == null));
            if (d != null) {
                subscriber.onNext(d);
            }
            subscriber.onCompleted();
        }
    }).subscribeOn(Schedulers.io());

网络

    private Observable<String> networkSource = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            String d = data[2];
            printLog(tvLogs, "", "----start check network data. value is null? " + (d == null));
            if (d != null) {
                subscriber.onNext(d);
            }
            subscriber.onCompleted();
        }
    }).subscribeOn(Schedulers.io());

从例子1我们知道,concat会三个数据源都会请求的。如何使得哪层有数据就用哪层的,之后就不走后面的逻辑了。
可以配合first()操作符来实现这样的效果。

Observable.concat(memorySource, diskSource, networkSource)
                        .first()
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Action1<String>() {
                            @Override
                            public void call(String s) {
                                printLog(tvLogs, "Getting data from ", s);
                            }
                        }, new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                throwable.printStackTrace();
                                printLog(tvLogs, "Error: ", throwable.getMessage());
                            }
                        });

需要注意的是如果 memorySource, diskSource, networkSource 返回的都 null,那么会报一个异常:java.util.NoSuchElementException: Sequence contains no elements......

可以使用 takeFirst 操作,即使都没有数据,也不会报异常。

Observable.concat(memorySource, diskSource, networkSource)
                        //first()-> if no data from observables will cause exception :
                        //java.util.NoSuchElementException: Sequence contains no elements
                        //takeFirst -> no exception
                        .takeFirst(new Func1<String, Boolean>() {
                            @Override
                            public Boolean call(String s) {
                                return s != null;
                            }
                        })
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Action1<String>() {
                            @Override
                            public void call(String s) {
                                printLog(tvLogs, "Getting data from ", s);
                            }
                        }, new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                throwable.printStackTrace();
                                printLog(tvLogs, "Error: ", throwable.getMessage());
                            }
                        });

除了通过 concat 操作符来实现缓存逻辑,也可使用switchIfEmpty详情可以查看我的博客


如果你觉得本文帮助到你,给我个关注和赞呗!

另外,我为 Android 程序员编写了一份:超详细的 Android 程序员所需要的技术栈思维导图

如果有需要可以移步我的 GitHub -> AndroidAll,里面包含了最全的目录和对应知识点链接,帮你扫除 Android 知识点盲区。 由于篇幅原因只展示了 Android 思维导图:
超详细的Android技术栈

  • 11
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiclaim

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值