一 前言
Ok,我们在上一篇RxJava2.X 源码分析(五):变换操作符的实现原理(上)中分析了RxJava2中转换操作符map的实现过程
本次我们将紧跟上篇的步伐,分析比map更为强大的flatMap操作符的实现流程
二 Demo
首先,我们还是老样子,先看一个demo:
Observable observable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(@NonNull ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
});
observable.flatMap(new Function>() {
@Override
public ObservableSource apply(@NonNull Integer integer) throws Exception {
return Observable.just(integer*integer);
}
}).subscribe(new Consumer() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
Log.i(TAG, ">>>data is : " + integer);
}
});
============================================================================
2021-02-04 09:32:06.714 14161-14161/com.example.myapplication D/flatMap:: 1
2021-02-04 09:32:06.714 14161-14161/com.example.myapplication D/flatMap:: 4
2021-02-04 09:32:06.714 14161-14161/com.example.myapplication D/flatMap:: 9
我们重点来看一下applay方法返回的类型,显然易见,Map()方法直接返回的是事件类型,如Integer类型,而flatMap()方法则是返回一个Observable类型;那么这个区别能提供怎样的能力呢? 1、比如连续两个串行的网络请求 2、如数据类型的中间转换等等,
也就是说,我们能以很自然流畅的方式在中间做一些转换,能做的事情很多哦。
我们开始进入正题,看下内部是如何实现的呢?从flatMap方法进去。
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) {
return flatMap(mapper, false);
}
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper, boolean delayErrors) {
return flatMap(mapper, delayErrors, Integer.MAX_VALUE);
}
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper, boolean delayErrors, int maxConcurrency) {
return flatMap(mapper, delayErrors, maxConcurrency, bufferSize());
}
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency");
ObjectHelper.verifyPositive(bufferSize, "bufferSize");
if (this instanceof ScalarCallable) {
@SuppressWarnings("unchecked")
T v = ((ScalarCallable<T>)this).call();
if (v == null) {
return empty();
}
return ObservableScalarXMap.scalarXMap(v, mapper);
}
return RxJavaPlugins.onAssembly(new ObservableFlatMap<T, R>(this, mapper, delayErrors, maxConcurrency, bufferSize));
}
这里经过重复的调用flatMap()方法,将一些参数传入进去:
- delayErrors:是否延迟错误处理
- maxConcurrency:最大的并发量
- bufferSize:队列的大小
Ok,最终调用了含有四个参数的flatMap()方法,我们重点看一下这个方法:
public final <R> Observable<R> flatMap(Functionsuper T, ? extends ObservableSourceextends R>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
//1、做一些值的判断,不符合规定我就报一场
ObjectHelper.requireNonNull(mapper, "mapper is null");
ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency");
ObjectHelper.verifyPositive(bufferSize, "bufferSize");
//2、判断我们的上游Obsevable是否是ScalarCallable类型,做特殊处理,我们的上游如果是Observable.just就会走这里(just方法返回的Observable是实现了ScalarCallable接口的)
if (this instanceof ScalarCallable) {
@SuppressWarnings("unchecked")
T v = ((ScalarCallable<T>)this).call();
if (v == null) {
return empty();
}
return ObservableScalarXMap.scalarXMap(v, mapper);
}
//3、OK,看到我们熟悉的方法了
return RxJavaPlugins.onAssembly(new ObservableFlatMap<T, R>(this, mapper, delayErrors, maxConcurrency, bufferSize));
在这里我们先来看一下Observable.just()这个方法:
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public static <T> Observable<T> just(T item) {
ObjectHelper.requireNonNull(item, "The item is null");
return RxJavaPlugins.onAssembly(new ObservableJust<T>(item));
}
public final class ObservableJust<T> extends Observable<T> implements ScalarCallable<T> {
private final T value;
public ObservableJust(final T value) {
this.value = value;
}
@Override
protected void subscribeActual(Observer<? super T> s) {
ScalarDisposable<T> sd = new ScalarDisposable<T>(s, value);
s.onSubscribe(sd);
sd.run();
}
@Override
public T call() {
return value;
}
}
这里的流程相信大家很熟悉了,就是对上游的Observable进行包装之后被下游的订阅后触发subscribeActual()方法,我们主要来看看这里的方法:
@Override
protected void subscribeActual(Observer<? super T> s) {
ScalarDisposable<T> sd = new ScalarDisposable<T>(s, value);
s.onSubscribe(sd);
sd.run();
}
这里对传入的Observer进行了包装,我们来看看ScalarDisposable这个类:
public final class ObservableScalarXMap {
......
public static final class ScalarDisposable<T>
extends AtomicInteger
implements QueueDisposable<T>, Runnable{
@Override
public void run() {
if (get() == START && compareAndSet(START, ON_NEXT)) {
observer.onNext(value);
if (get() == ON_NEXT) {
lazySet(ON_COMPLETE);
observer.onComplete();
}
}
}
.......
}
ScalarDisposable是ObservableScalarXMap(之后会详细说一下这个类) 这个类的内部类,而且它实现了Runable接口,重写了run()方法;在这里调用了Observer里的方法实现事件的接收;事实上这里也的确在ObservableJust被订阅时调用了(subscribeActua()方法里)。
Ok,分析完Observabvle.just()方法,我们思路回过来,继续看flatMap()里的实现就简单多了:
public final <R> Observable<R> flatMap(Functionsuper T, ? extends ObservableSourceextends R>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
//1、做一些值的判断,不符合规定我就报一场
ObjectHelper.requireNonNull(mapper, "mapper is null");
ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency");
ObjectHelper.verifyPositive(bufferSize, "bufferSize");
//2、判断我们的上游Obsevable是否是ScalarCallable类型,做特殊处理,我们的上游如果是Observable.just就会走这里
if (this instanceof ScalarCallable) {
@SuppressWarnings("unchecked")
T v = ((ScalarCallable<T>)this).call();
if (v == null) {
return empty();
}
return ObservableScalarXMap.scalarXMap(v, mapper);
}
//3、OK,看到我们熟悉的方法了
return RxJavaPlugins.onAssembly(new ObservableFlatMap<T, R>(this, mapper, delayErrors, maxConcurrency, bufferSize));
这里分两种情况:
-
第一种:ObservableScalarXMap.scalarXMap(v, mapper)
当上游Obsevable是ScalarCallable类型,就会走这里,上面分析过,Observable.just返回的就是ScalarCallable类型的Observable -
第二种: return RxJavaPlugins.onAssembly(new ObservableFlatMap<T, R>(this, mapper, delayErrors, maxConcurrency, bufferSize));
我们的demo就是属于第二种情况。
我们先来看第一种情况:ObservableScalarXMap.scalarXMap(v, mapper),首先对两个参数要有所理解,v其实就是just()方法里面出入的值,mapper就是我们new出来的function类了。OK,前面在讲just()方法原理的时候出现过了ObservableScalarXMap类,just()方法里利用ObservableScalarXMap类里的Observer包装类对下游Observer类进行包装,接收上游Observable下发的数据,不懂流程的小伙伴可以倒回去看看just()的执行过程。
我们来看看ObservableScalarXMap的scalarXMap()方法:
public static <T, U> Observable<U> scalarXMap(T value,
Function<? super T, ? extends ObservableSource<? extends U>> mapper) {
//对上有Observerable进行包装
return RxJavaPlugins.onAssembly(new ScalarXMapObservable<T, U>(value, mapper));
}
static final class ScalarXMapObservable<T, R> extends Observable<R> {
final T value;
final Function<? super T, ? extends ObservableSource<? extends R>> mapper;
ScalarXMapObservable(T value,
Function<? super T, ? extends ObservableSource<? extends R>> mapper) {
this.value = value;
this.mapper = mapper;
}
@SuppressWarnings("unchecked")
@Override
public void subscribeActual(Observer<? super R> s) {
ObservableSource<? extends R> other;
try {
//获取applay方法里的返回值(Observable)
other = ObjectHelper.requireNonNull(mapper.apply(value), "The mapper returned a null ObservableSource");
} catch (Throwable e) {
EmptyDisposable.error(e, s);
return;
}
if (other instanceof Callable) {
R u;
try {
u = ((Callable<R>)other).call();
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
EmptyDisposable.error(ex, s);
return;
}
if (u == null) {
EmptyDisposable.complete(s);
return;
}
//这个类很熟悉吧,没错就是just()方法原理的出现过的,这里ScalarDisposable实现了Runnable接口,在run方法里下游Observer会对上有Observable下发的数据进行接收。
ScalarDisposable<R> sd = new ScalarDisposable<R>(s, u);
s.onSubscribe(sd);
sd.run();
} else {
other.subscribe(s);
}
}
}
其实很简单,这里也分两种情况:
- 第一种,如果applay方法返回的是实现了Callable接口的,就会按照just()方法的原理流程走
- 第二种,如果不是,就直接执行subscribe()方法按照正常的流程走。
Ok,现在我们来根据Demo里的方法走,flatMap()返回
return RxJavaPlugins.onAssembly(new ObservableFlatMap<T, R>(this, mapper, delayErrors, maxConcurrency, bufferSize));
我们先来看看ObservableFlatMap这个类:
public final class ObservableFlatMap<T, U> extends AbstractObservableWithUpstream<T, U> {}
可以看到,ObservableFlatMap的包装以之前的线程实现类型,同样是继承了AbstractObservableWithUpstream类,也就是说,内部有source存储我们上游的Observable
构造方法比较简单,主要就是赋值:
public ObservableFlatMap(ObservableSource<T> source,
Functionsuper T, ? extends ObservableSourceextends U>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
super(source);
this.mapper = mapper;
this.delayErrors = delayErrors;
this.maxConcurrency = maxConcurrency;
this.bufferSize = bufferSize;
}
Ok,我们看重点subscribeActual方法,其触发是在下游Observer调用subscribe订阅时
@Override
public void subscribeActual(Observer<? super U> t) {
//1、同样是对Scalar的处理
if (ObservableScalarXMap.tryScalarXMapSubscribe(source, t, mapper)) {
return;
}
//2、重点在这里,t为下游的Observer,mapper为我们的funcation,T为接收类型,R为转换后类型
source.subscribe(new MergeObserver<T, U>(t, mapper, delayErrors, maxConcurrency, bufferSize));
}
看2处代码:source为上游Observable,也就是我们这里new了一个中间Obsever来订阅上游Observable,然后中间Observer接收到上游下发的数据,猜测还是调用来mapper.apply获得转换后的Obsevable类型,然后还是看代码吧:
static final class MergeObserver<T, U> extends AtomicInteger implements Disposable, Observer {
...
MergeObserver(Observersuper U> actual, Functionsuper T, ? extends ObservableSourceextends U>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
//1、下游的Observer,用于后面数据的传递
this.actual = actual;
//2、funcation,用于转换函数的操作
this.mapper = mapper;
this.delayErrors = delayErrors;
//3、并发数,因为中间我们转换后的Obsevable可能接收一个值然后产生多个值,如调用Observable.fromArray(),
this.maxConcurrency = maxConcurrency;
this.bufferSize = bufferSize;
//4、存储apply返回的Observable
if (maxConcurrency != Integer.MAX_VALUE) {
sources = new ArrayDeque<? extends U>>(maxConcurrency);
}
this.observers = new AtomicReference[]>(EMPTY);
}
}
OK,看完了构造方法,我们看下MergeObserver的onSubscribe以及onXXX(),执行完source.subscribe(new MergeObserver<T, U>(t, mapper, delayErrors, maxConcurrency, bufferSize));后,我们的onSubscribe会被调用,然后就是onXXX();
public void onSubscribe(Disposable s) {
if (DisposableHelper.validate(this.s, s)) {
this.s = s;
actual.onSubscribe(this);
}
}
在onSubscribe中只是简单的调用actual.onSubscribe(this)进行事件的传递,同时存储Disposable进行Disposable事件的管理。
OK,那么重点应该在onNext(T t):
@Override
public void onNext(T t) {
// safeguard against misbehaving sources
if (done) {
return;
}
ObservableSource<? extends U> p;
try {
//1、调用mapper.apply获得转换函数的返回值Observable。
p = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper returned a null ObservableSource");
} catch (Throwable e) {
//2、发生异常时终止
Exceptions.throwIfFatal(e);
s.dispose();
onError(e);
return;
}
//3、如果你明确设置了maxConcurrency,需要入队列进行排队处理,因为要控制并发量
if (maxConcurrency != Integer.MAX_VALUE) {
synchronized (this) {
if (wip == maxConcurrency) {
sources.offer(p);
return;
}
wip++;
}
}
//4、内部订阅处理,因为返回的p是observable,所以内部肯定还需要通过下游的Observer订阅它,这样数据流才能继续下发。
subscribeInner(p);
}
OK,那么我们继续分析subscribeInner,看内部如何订阅
void subscribeInner(ObservableSourceextends U> p) {
for (;;) {
if (p instanceof Callable) {
tryEmitScalar(((Callableextends U>)p));
if (maxConcurrency != Integer.MAX_VALUE) {
synchronized (this) {
p = sources.poll();
if (p == null) {
wip--;
break;
}
}
} else {
break;
}
} else {
//1、this及为我们的MergeObserver对象,再次wrapper,
InnerObserver<T, U> inner = new InnerObserver<T, U>(this, uniqueId++);
if (addInner(inner)) {
//触发订阅,如此,我们下游的Observer就开始等着接收数据流了。
p.subscribe(inner);
}
break;
}
}
}
OK,基本上整个flatMap的转换流程也就分析完了,其余太细的点,我们就不继续深入,因为本次我们的目的就是了解其实现流程即可。在宏观上进行把控。
三 总结
Ok,根据上面的分析,其实对于flatMap的操作过程我们已经很清楚了,其跟map基本一样,通过在中间使用装饰者模式插入一个中间的Observable和Observe,你可以想象为代理。
代理Observable做的事就是接收下游Obsever的订阅事件,然后通过代理Obsever订阅上游Observer,然后在上游Observer下发数据給代理Observer时,通过先调用mapper.apply转换回调函数获得转换后的Observable,内部通过下游Observer再次订阅,然后转换后返回的Observable下发数据给下游Obsever。
OK,通过从第一篇到本篇,我们不难发现,基本都是一样的模式,通过装饰者模式中间产生一个Observable和Observer,完成订阅事件的传递以及下发数据流的传递,进过我们中间产生的Observable和Observer时,根据具体需求做一些操作。
理解了这些,相信你再去看其他操作符的代码时,按这个思路去看,基本都是Ok的。
希望通过本篇的学习,大家对于RxJava2的内部实现的一些流程更为熟悉。