RxJava zip操作符源码分析

zip操作符允许接受多个ObservableSource发射的数据,并能够将他们重新组合并重新发射的一种操作符。常见的使用方式:

首先传入若干个ObservableSource,然后每个ObservableSource都能通过observer.onNext来发射数据,最终在Function接口实现方法中可以获取到这些数据,并做一个重新整合或其他操作,然后返回。比如这里我将获取的值相加然后返回,最终在Observer.onNext中能获取到值123:

在这里插入图片描述


源码分析

看看zip的实现:

在这里插入图片描述

将传入的Function3实现接口对象封装成Function对象:

在这里插入图片描述

其他的ObservableSource对象不动,继续跟入:

在这里插入图片描述

返回一个ObservableZip对象,并将开始创建的所有对象交给它。

调用它的subscribe方法并传入Observer对象:

它没有subscribe方法,这个方法是在父类Observable,而父类又会调用它的subscribeActual方法:

在这里插入图片描述

其实到这就差不多快结束了。zip的代码流程并不复杂,而是采用的一种算法比较复杂,这种算法可以让所有传入的Observer执行onNext时,在Function中达到一一对应的效果。

比如最上面的例子是3个ObservableSource同时发射了2个数据,重新举例:

这个是2个ObservableSource同时发射2个数据,接受者会接受什么呢?输出是

12
45

在这里插入图片描述

如果9个(最多只能9个)ObservableSource同时发射m个数据,BiFunction要怎么一一对应呢?

回到subscribeActual方法实现,最下面会将自定义的Observer接口对象s和zipper(即BiFunction包装类)传给ZipCoordinator构造方法然后生成ZipCoordinator对象,并调用subscribe方法然后将Observer集合传入:

在这里插入图片描述

ZipCoordinator的构造方法:
在这里插入图片描述

在这里插入图片描述

以一开始的3个ObservableSource发射同时发射2个数据为例:

可以看到这里生成了一个ZipObserver数组,数量为count值,而count值为外部传入的sources的长度,这里创建了3个ObservableSource,所以count为3,循环遍历new出对象,并将ZipCoordinator传入它的构造方法。

调用

actual.onSubscribe(this);

actual即外部传入的自定义Observer接口对象:

在这里插入图片描述

最后调用

for (int i = 0; i < len; i++) {
            if (cancelled) {
                return;
            }
            sources[i].subscribe(s[i]);
        }

这个source即为外部传入的3个ObservableSource对象,这样看行了,这个循环调用可以看做这样:

sources[0].subscribe(s[0]);
sources[1].subscribe(s[1]);
sources[2].subscribe(s[2]);

接下来的所有代码执行就这3句话

第一句代码:

sources[0].subscribe(s[0]);

调用subscribe方法并传入ZipObserver对象:

在这里插入图片描述

调用ZipObserver的onNext方法,传入1,看看onNext的实现:

在这里插入图片描述

将1加入到queue中,queue是构造方法中初始化的SpscLinkedArrayQueue,一种存取数据的数据结构:
在这里插入图片描述

调用

parent.drain()

parent即为传入的ZipCoordinator,看看drain方法,这个drain方法很重要,几乎所有的工作都会由drain方法完成:

在这里插入图片描述在这里插入图片描述

1:生成一个临时ZipObserver数组zs
2: a = actual,即a为外部Observer接口实现对象
3:生成一个临时数组os

回到刚刚的代码执行,将1存入ZipObserver的queue中后,调用parent的drain方法。执行死循环,可以看到循环遍历ZipObserver数组,取出第一个ZipObserver的queue调用poll:

在这里插入图片描述
取出值,这是当然是有值的,是刚刚传入的1,判断非空,调用下面的os[i]=1,i这时为0,即os[0]=1,i++后继续循环,此时取出第二个ZipObserver,它的queue中肯定没有值,因为刚刚存值的是第一个ZipObserver的queue,所以判断为null,走下面的else语句,将emptyCount++:

在这里插入图片描述

再次循环,第三个ZipObserver和第二个一样,queue里没值,所以一样
emptyCount++,内循环结束,走到下面的代码:

在这里插入图片描述

emptyCount不为0为2,break退出,回去执行第二个onNext,即:

在这里插入图片描述

此时传入了4,一样的代码将4添加到第一个ZipObserver的queue中,然后调用drain,又进入了双层循环,首先判断os[i]是否为0,因为i被重置为0,即os[0],而os[0]刚刚已经被赋值了,所以不会走if的语句,else语句中是为错误而设置,暂且不用管。i++后重新从第二个,第三个ZipObserver的queue中取值,取的值是null,所以emptyCount++,同样的判断emptyCount!=0,break!

这样,第一个ObservableSource的subscribe方法执行完了,调用了:

	onNext(1)
	onNext(4)

结果为:

第一个ZipObserver的queue中存有1个值:4
os数组中有个值:1

第一句代码执行完毕


第二句代码执行:

sources[1].subscribe(s[1]);

继续第二个ObservableSource的subscribe调用:

在这里插入图片描述

此时的Observer对象是第二个ZipObserver了,调用它的onNext方法,与之前一样,先将2添加到queue中,只不过这次是添加到第二个ZipObserver的queue中,然后调用parent.drain方法,同样的,I初始化为0,os[0]有值,是1,i++后循环到第二个ZipObserver,此时os[i],即os[1]没有值,进入if语句,此时的z是第二个ZipObserver,它的queue中是有值的,刚存的2,取出并将os[1]赋值为2,i++后循环第三个ZipObserver,os[2]为null,进入if语句,queue中没有值,取了个null,然后一样的将emptyCount++,执行break

继续执行onNext(5),存入第二个ZipObserver的queue中,执行parent.drain,进入循环:

for (ZipObserver<T, R> z : zs) {
			...
}

循环第一次,os[0]有值(i每次进入内循环时都会被重置为0),不进入if语句,i++,循环第二次,os[1]有值,刚刚赋值的2,不进入if语句,i++,循环第三次,第三个ZipObserver的queue同样取了个null,emptyCount++。结束循环,emptyCount != 0成立,break

此时第二句代码也结束了,现在的结果是:

第一个ZipObserver的queue中存有1个值:4
第一个ZipObserver的queue中存有1个值:5
os数组中有个值:1,2

第二句代码执行完毕

第三句代码执行:

sources[1].subscribe(s[1]);

在这里插入图片描述

此时的Observer对象是第三个ZipObserver了,调用它的onNext(3),将3加入到它的queue中,即加入到第三个ZipObserver的queue中,然后一样调用parent.drain,之前出现的所有parent.drain都是同一个对象调用同一个方法,因为传入的就是同一个对象。

同样的for循环:

for (ZipObserver<T, R> z : zs) {
	....
}

os[0]和os[1]都有值,if语句进不去,i++,第三次循环时,即此时z为第三个ZipObserver,os[2]为null,进入循环,queue中有值,刚刚存入的3,取出赋值:os[3]=3.循环结束。此时os数组中3个值,分别是1,2,3。并且发现emptyCount==0!
回顾一下:第一次,第二次循环因为os[0]和os[1]有值无法进入if循环,emptyCount没有机会+1,第三次queue中有值,不走下面的emptyCount++代码,因此跳过if判断:

在这里插入图片描述

走下面的代码:

在这里插入图片描述

调用zipper的apply方法,zipper即一开始传入的Function3的包装类,调用它的apply方法:

在这里插入图片描述

这里将3个数据一次作为f的apply方法的参数一次传入,这个f是啥?f即为一开始传入的接口实现对象:

在这里插入图片描述

然后由开发者做处理,这里我将他们拼接后返回,返回值为v:

在这里插入图片描述

调用a的onNext方法,并将值作为参数传入,a 即为外部传入的Obserer接口实现对象:

在这里插入图片描述

继续执行

Arrays.fill(os, null);

将os数组的值清空。

此时:

第一个ZipObserver的queue中存有1个值:4
第二个ZipObserver的queue中存有1个值:5
os数组中无值

再次进入循环,因为这是个3层死循环!再次遍历ZipObserver数组,此时os数组为空了,因此从第一个ZipObserver依次取值,第一个ZipObserver的queue中有值,取出并os[0] = 4,i++,遍历第二次。

第二个ZipObserver的queue中有值,取出并os[1] = 5,遍历第三次,此时第三个ZipObserver的queue中为null,emptyCount++,后面都一样的:break退出循环。

此时:

第一个ZipObserver的queue中无值
第二个ZipObserver的queue中无值
os数组中有值,是4,5

继续执行onNext(6),存入第三个ZipObserver的queue中,执行parent.drain,进入循环。os[0]和os[1]都有值,if语句进不去,遍历第三次,从第三个ZipObserver的queue中取出值6,然后os[3]=6。结束循环emptyCount没有机会+1,因此是0,与之前相同,跳过:

在这里插入图片描述

将os数组中的值取出交由zipper的apply方法处理,又和之前一样,交由开发者在Function3接口对象的apply方法中处理,然后返回,调用a.onNext并将值传入方法。随后调用

Arrays.fill(os, null);

再次将os数组清空

再次进入循环,此时:

	第一个ZipObserver的queue中无值
	第二个ZipObserver的queue中无值
	第三个ZipObserver的queue中无值
	os数组中无值

然后从3个queue中都取不到所以emptyCount加3次,最终因为不等于0导致break退出循环

第三句代码执行完毕


总结:

3个ObservableSource调用subscribe方法:

第一个ObservableSource调用subscribe:

第一个ZipObserver.onNext(1)后:

	第一个ZipObserver的queue中无值
	第二个ZipObserver的queue中无值
	第三个ZipObserver的queue中无值
	os数组的值为:1

第一个ZipObserver.onNext(4)后:

	第一个ZipObserver的queue中的值为4
	第二个ZipObserver的queue中无值
	第三个ZipObserver的queue中无值
	os数组的值为:1

第二个ZipObserver.onNext(2)后:

	第一个ZipObserver的queue中的值为4
	第二个ZipObserver的queue中无值
	第三个ZipObserver的queue中无值
	os数组的值为:1,2

第二个ZipObserver.onNext(5)后:

	第一个ZipObserver的queue中的值为4
	第二个ZipObserver的queue中的值为5
	第三个ZipObserver的queue中无值
	os数组的值为:1,2

第三个ZipObserver.onNext(3)后:

	第一个ZipObserver的queue中的值为4
	第二个ZipObserver的queue中的值为5
	第三个ZipObserver的queue中无值(3加入后很多就会取出放入os数组)
	os数组的值为:1,2,3
	--->(1、2、3输出)
	第一个ZipObserver的queue中的值为4
	第二个ZipObserver的queue中的值为5
	第三个ZipObserver的queue中无值
	os数组无值
	--->(再次循环)
	第一个ZipObserver的queue中无值
	第二个ZipObserver的queue中无值
	第三个ZipObserver的queue中无值
	os数组的值为,4,5

第三个ZipObserver.onNext(6)后:

	第一个ZipObserver的queue中无值
	第二个ZipObserver的queue中无值
	第三个ZipObserver的queue中无值(6加入后很多就会取出放入os数组)
	os数组的值为:4,5,6
	--->(4、5、6输出)

不论多少个ObservableSource,每个ObservableSource都会绑定一个ZipObserver。然后通过以上算法达到一一对应的关系。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哒哒呵

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

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

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

打赏作者

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

抵扣说明:

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

余额充值