由 RxJava Zip 操作符引起的串行并行操作

今天用到了 RxJava2 中 zip 操作符,目的是下载两张图片后合成为一张图片。具体代码不就贴出来了,简单提供一个小的操作流

模拟两个下载图片的 Flowable ,代码如下 (kotlin)

        val just = Flowable.create<String>({
            XLog.e("是否是主线程 1 : ${Looper.getMainLooper() == Looper.myLooper()}")
            Thread.sleep(500)
            it.onNext("1")
        }, BackpressureStrategy.BUFFER)
//            .delay(500, TimeUnit.SECONDS)

        val a = Flowable.create<String>({
            Thread.sleep(1000)
            XLog.e("是否是主线程 2 : ${Looper.getMainLooper() == Looper.myLooper()}")
            it.onNext("a")
        }, BackpressureStrategy.BUFFER)

这里计划用 delay 进行延迟发送,但与 zip 操作符不能相结合。下面贴出简单的 zip 

        Flowable.zip<String, String, String>(
            just,
            a,
            BiFunction { s, s2 ->
                XLog.e("是否是主线程 3 : ${Looper.getMainLooper() == Looper.myLooper()}")
                XLog.e("time2 " + (System.currentTimeMillis() - l))
                s + s2
            })
            .execute(this)
            .subscribe { s ->
                XLog.e("是否是主线程 4 : ${Looper.getMainLooper() == Looper.myLooper()}")
                XLog.e("time2 $s")
            }

这里的 l 对象为 val l = System.currentTimeMillis() 

预想的结果是达到了,但是查看 time2 的时间时,有如下 log

 E/Base_XLog: 是否是主线程 2 : false
 E/Base_XLog: 是否是主线程 3 : false
 E/Base_XLog:   time2 1505
 E/Base_XLog: 是否是主线程 4 : true
 E/Base_XLog: time2 1a

整个过程的运行时间为 1505 ,也就是说是 just 和 a 两个串行运行的时间,由此可以了解到 zip 操作符为串行将 传入的 Publisher 依次运行,查看源码 subscribeActual 可以看出,确实是 for 循环,一次执行 Publisher ,最后再将结果发射出去。(不太了解源码的可以查看我以前的文章,subscribeActual 是一个重要的函数)

    public void subscribeActual(Subscriber<? super R> s) {
        Publisher<? extends T>[] sources = this.sources;
        int count = 0;
        if (sources == null) {
            sources = new Publisher[8];
            for (Publisher<? extends T> p : sourcesIterable) {
                if (count == sources.length) {
                    Publisher<? extends T>[] b = new Publisher[count + (count >> 2)];
                    System.arraycopy(sources, 0, b, 0, count);
                    sources = b;
                }
                sources[count++] = p;
            }
        } else {
            count = sources.length;
        }

        if (count == 0) {
            EmptySubscription.complete(s);
            return;
        }

        ZipCoordinator<T, R> coordinator = new ZipCoordinator<T, R>(s, zipper, count, bufferSize, delayError);

        s.onSubscribe(coordinator);

        coordinator.subscribe(sources, count);
    }

这样操作倒是简单了许多,但是时间上消耗的就多了。

由此,我想到了 RxJava2 有一个 toList 操作符,可以收集原始 Flowable 等发射的所有数据到一个列表,然后返回这个列表。这样岂不是可以并发运行了,如此就有如下代码

        val l = System.currentTimeMillis()
        Flowable.fromIterable(mutableListOf("1", "a"))
            .map {
                return@map it
            }
            .flatMap { s ->
                return@flatMap Flowable.just(s).observeOn(Schedulers.io())
                    .map {
                        Thread.sleep(2000)
                        return@map "request done:$s"
                    }
            }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .toList()
            .toFlowable()
            .map { list ->
                var s = ""
                list.forEach {
                    s += it
                }
                return@map s
            }
            .subscribe {
                XLog.e(it)
                XLog.e("  time2 " + (System.currentTimeMillis() - l))
                XLog.e("是否是主线程 4 : ${Looper.getMainLooper() == Looper.myLooper()}")
            }

日志如下

 E/Base_XLog: request : 1 request : a
 E/Base_XLog:   time2 2014
 E/Base_XLog: 是否是主线程 4 : true

这里可以看到,运行时间为 2014 ,完美符合预期。

 

RxJava2 的操作符实在是多,有些我们几乎见过,所以需要对整体有个认识,主要的有如下几种:

创建操作:just()、create()、fromArray()、defer()、interval()、range() 等

变换操作符:buffer()、map()、flatMap()、concatMap()、groupBy() 等

过滤操作符列表:filter()、skip()、take()、elementAt() 即它们的一些扩展等

聚合操作符:concat()、count()、reduce()、toList()、toMap() 等

连接操作符:ConnectableObservable.connect()、Observable.publish()、Observable.replay()、ConnectableObservable.refCount() 等

还有一些运算、比较、错误处理,也包含一些 do 开头的运算符。

不需要全部都记下来,大致有个印象,使用的时候可以查看源码或文档即可。

 

笔者认为 RxJava 早已到了 Android 开发的顶峰了,一点不了解的有些说不过去了,因此赶快抓紧了解其 API,更要阅读其源码,了解其机制才是。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值