前言:

RxJava想必很多人都用过了,其实也是一早就接触过这个框架了,但是最近看了下一些关于是否需要使用RxJava的文章,对于RxJava的优点缺点有了更深的理解,然后看了论坛上有朋友提到很难理解Map,flatMap的区别,所以突然兴致来了,想写一点点东西,从源码出发简单的聊一下这两个方法的区别以及使用,通过通俗易懂的方式使大家能轻松简单的理解他们,好的让我们开始吧:

首先我看来看看RxJava的一些基本概念:

RxJava 简介:

RxJava是 ReactiveX 在 Java 上的开源的实现。RxJava可以轻松处理不同运行环境下的后台线程或UI线程任务的框架。RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。

Observable(可观察者,即被观察者) 和 Subscriber(订阅者)是两个主要的类。在 RxJava 上,一个 Observable 是一个发出数据流或者事件的类,Subscriber 是一个对这些发出的 items (数据流或者事件)进行处理(采取行动)的类。

Observable 和Observer 通过 subscribe() 方法实现订阅关系。一个 Observable 的标准流发出一个或多个item,然后成功完成或者出错。一个 Observable 可以有多个 Subscribers,并且通过 Observable 发出的每一个 item,该 item 将会被发送到 Subscriber.onNext() 方法来进行处理。一旦 Observable 不再发出 items,它将会调用 Subscriber.onCompleted() 方法,或如果有一个出错的话Observable 会调用 Subscriber.onError() 方法。

RxJava里面两个关键的概念:Observable 与 Observer 即被观察者,与观察者,他们在RxJava里面对应的类分别为:class Observable 与 interface Observer ,Observer是 interface 里面定义了我们最经常见的三个方法,

public interface Observer {
void onCompleted();
void onError(Throwable e);
void onNext(T t);
}

但是我们在代码中一般不直接使用他,而是在代码里面经常看见实现了他的抽象类:

public abstract class Subscriber implements Observer, Subscription {
// represents requested not set yet
private static final Long NOT_SET = Long.MIN_VALUE;
private final SubscriptionList subscriptions;
private final Subscriber> subscriber;
/* protected by `this` */
private Producer producer;
/* protected by `this` */
private long requested = NOT_SET; // default to not set
protected Subscriber() {
this(null, false);
}
//省略以下方法
}

因为他是 abstract 也不能直接new出来,我们在使用中经常会new 他的匿名类来进行使用(注意:new匿名的abstract类并不是直接new 了abstract,底层而是会生成一个类,这个类继承了abstract,这个有机会展开给大家说)

Subscriber subscriber = new Subscriber() {
@Override
public void onNext(String s) {
Log.d("Rxjava", "Item: " + s);
}
@Override
public void onCompleted() {
Log.d("Rxjava", "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d("Rxjava", "Error!");
}
};

其中还有一个重要的概念就是 Observable.OnSubscribe 这个表示的是被监听者与监听者绑定以后会触发 OnSubscribe 里面的 call 方法,我们一般在 call 方法里面进行对于监听者 subscribe 的三个方法 onNext ,onCompleted,onError 的触发调用,使得整个调用过程像”链式“一样进行。

好了,我们现在再来看看RxJava的最最基本使用(😆大侠可以直接绕道走了),通过最最基本的使用我们来说一说基本的调用流程:

public void testCreate(){
Observable observable = Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
Subscriber subscriber = new Subscriber() {
@Override
public void onNext(String s) {
Log.d("Rxjava", "Item: " + s);
}
@Override
public void onCompleted() {
Log.d("Rxjava", "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d("Rxjava", "Error!");
}
};
observable.subscribe(subscriber);
}

首先创建一个被观察者 observable ,再创建一个观察者 subscriber 通过

observable.subscribe(subscriber);

方法来进行关联和调用,一旦关联以后就是调用到 Observable 的 call 方法,会把 subscribe 传递到 call 方法的参数里面(大家一定要理解这个,不要只记住调用步骤就完了,因为这个是你理解RxJava的基础)

为什么是这个步骤了,让我从代码中找到答案,其实很简单:

static Subscription subscribe(Subscriber super T> subscriber, Observable observable) {
// The code below is exactly the same an unsafeSubscribe but not used because it would
// add a significant depth to already huge call stacks.
try {
// allow the hook to intercept and/or decorate
hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);
} catch (Throwable e) {
//省略以下代码
}
}

而 hook.onSubscribeStart 只是返回 observable.onSubscribe 然后调用它的 call 方法,而这个又是什么呢?

protected Observable(OnSubscribe f) {
this.onSubscribe = f;
}

只不过是Observable.create 出来的 OnSubscribe ,

public interface OnSubscribe extends Action1> {
// cover for generics insanity
}
public interface Action1 extends Action {
void call(T t);
}

OnSubscribe 也就是我们create时候的匿名类:

Observable observable = Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});

所以现在执行就很明显了, 现在 observable.subscribe(subscriber); 把 subscribe 传入到你实现的 OnSubscribe 的 call 方法里面,然后调用 call 方法

好了有了这个基础,我们再来看看Map方法是怎么实现数据转换的,首先我们看看Map的基本使用:

Observable observable = Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
subscriber.onNext("333");
Log.d("Rxjava", "call observable");
}
});
observable.map(new Func1() {
@Override
public Integer call(String number) { // 参数类型 String
return Integer.parseInt(number);
}
}).subscribe(new Action1() {
@Override
public void call(Integer number) {
Log.d("Rxjava", "number:" + number.getClass());
}
});

为了大家好理解,我还是分开来实现,首先 Observable.create 了一个被监听者,然后 Map 转换,然后再 subscribe 订阅触发事件,

我们先看看 observable.map 里面做了什么:

public final Observable map(Func1 super T, ? extends R> func) {
return lift(new OperatorMap(func));
}

通过 Map 里面的转换步骤 Func1 new了一个 OperatorMap ,再看看这个是什么:

public final class OperatorMap implements Operator {
final Func1 super T, ? extends R> transformer;
public OperatorMap(Func1 super T, ? extends R> transformer) {
this.transformer = transformer;
}
@Override
public Subscriber super T> call(final Subscriber super R> o) {
MapSubscriber parent = new MapSubscriber(o, transformer);
o.add(parent);
return parent;
}
static final class MapSubscriber extends Subscriber {
final Subscriber super R> actual;
final Func1 super T, ? extends R> mapper;
boolean done;
public MapSubscriber(Subscriber super R> actual, Func1 super T, ? extends R> mapper) {
this.actual = actual;
this.mapper = mapper;
}
@Override
public void onNext(T t) {
R result;
try {
result = mapper.call(t);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
unsubscribe();
onError(OnErrorThrowable.addValueAsLastCause(ex, t));
return;
}
actual.onNext(result);
}
//省略以下
}

这个 OperatorMap 有一个 MapSubscriber 这个是作为一个转接的 Subscriber ,因为你的数据流是通过被监听者的 Observable.OnSubscribe call 触发然后经过 Map 里面的 Fun1 进行转换以后再到最终的 subscriber ,这个 MapSubscriber 就起到这么一个作用,再看看 lift 函数做点什么

public final Observable lift(final Operator extends R, ? super T> operator) {
return new Observable(new OnSubscribeLift(onSubscribe, operator));
}

又 new 了一个 Observable ,里面的参数是 new OnSubscribeLift(onSubscribe, operator) ,我们再看看 OnSubscribeLift 是什么:

public final class OnSubscribeLift implements OnSubscribe {
static final RxJavaObservableExecutionHook hook = RxJavaPlugins.getInstance().getObservableExecutionHook();
final OnSubscribe parent;
final Operator extends R, ? super T> operator;
public OnSubscribeLift(OnSubscribe parent, Operator extends R, ? super T> operator) {
this.parent = parent;
this.operator = operator;
}
@Override
public void call(Subscriber super R> o) {
try {
Subscriber super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
parent.call(st);
} catch (Throwable e) {
// localized capture of errors rather than it skipping all operators
// and ending up in the try/catch of the subscribe method which then
// prevents onErrorResumeNext and other similar approaches to error handling
Exceptions.throwIfFatal(e);
st.onError(e);
}
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// if the lift function failed all we can do is pass the error to the final Subscriber
// as we don't have the operator available to us
o.onError(e);
}
}
}

他实现了 OnSubscribe 了所以new 出来是没有问题的,因为被监听者的构造方法只是要 OnSubscribe 这个参数

protected Observable(OnSubscribe f) {
this.onSubscribe = f;
}

OnSubscribeLift 利用原来的 OnSubscribe 方法(原数据流最开始的执行方法)与new出来 ** OperatorMap** 为构造函数重新生成了一个 OnSubscribe,

整个 Map 函数的的过程就是new了一个新的被监听者 Observable ,然后里面的监听方法 onSubscribe 就是新生成的 OnSubscribeLift

然后执行下面语句会进行调用 Observable.OnSubscribe 的call 方法

observable.subscribe(subscriber);

也就是调用了 OnSubscribeLift 里面的 call 方法,里面会调用到 OperatorMap 里面的call方法

Subscriber super T> st = hook.onLift(operator).call(o);

operator 里面的call方法 o 变量为监听者 Subscriber ,transformer变量就是 new operator 是传入的 Func1 也就是Map里面的转换步骤 ,通过这两个变量生成了 this.actual 与 this.mapper

public Subscriber super T> call(final Subscriber super R> o) {
MapSubscriber parent = new MapSubscriber(o, transformer);
o.add(parent);
return parent;
}

这里面用这两个参数new出了一个 MapSubscriber 然后返回给 st 变量,然后调用 parent.call(st); 这个 parent 就是我们new OnSubscribeLift 的指定的原监听者的 OnSubscribe ,也就是要调用原被监听者的 OnSubscribe 的 call 函数来执行第一个”数据流“(这个也是正常现象Map只是转换,数据流还是应该从头进行然后经过Map最后到被监听者),只不过是传入的参数为 MapSubscriber,这个对象我们上面大概提到了作为一个桥接的Subscriber使用

public void call(Subscriber super String> subscriber) {
subscriber.onNext("333");
}

这个会”链接“调用到 MapSubscriber 的 onNext 方法并把原数据 ”333“ 传入,

@Override
public void onNext(T t) {
R result;
try {
result = mapper.call(t);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
unsubscribe();
onError(OnErrorThrowable.addValueAsLastCause(ex, t));
return;
}
actual.onNext(result);
}

前面说了 this.mapper 为转换函数 Fun1 ,mapper.call(t); 即调用Map的中转函数进行转换

public Integer call(String number) { // 参数类型 String
return Integer.parseInt(number);
}

然后再调用 actual 的 onNext 把转换的参数传进去,actual 上面也说了就是原 subscriber ,调用它的call 方法

new Action1() {
@Override
public void call(Integer number) {
Log.d("Rxjava", "number:" + number.getClass());
}
})

这里有点疑问不是调用 onNext 方法么,怎么调用到了 call 方法呢

接着看:

public final Subscription subscribe(final Action1 super T> onNext) {
if (onNext == null) {
throw new IllegalArgumentException("onNext can not be null");
}
Action1 onError = InternalObservableUtils.ERROR_NOT_IMPLEMENTED;
Action0 onCompleted = Actions.empty();
return subscribe(new ActionSubscriber(onNext, onError, onCompleted));
}

subscribe 方法里面会把 Action1 super T> onNext 封装成一个 ActionSubscriber 再进行 subscribe 调用,

public final class ActionSubscriber extends Subscriber {
final Action1 super T> onNext;
final Action1 onError;
final Action0 onCompleted;
public ActionSubscriber(Action1 super T> onNext, Action1 onError, Action0 onCompleted) {
this.onNext = onNext;
this.onError = onError;
this.onCompleted = onCompleted;
}
@Override
public void onNext(T t) {
onNext.call(t);
}
}

ActionSubscriber 的 onNext 方法执行了 Action1 的 call 方法,这样一来就全都对应上了

最后总结一下:Map 方法其实就是构造了一个新的 Observable 与 一个新的 Observable.OnSubscribe (OnSubscribeLift),OnSubscribeLift 执行的时候会生成一个 MapSubscriber ,然后会调用原 Observable.OnSubscribe 方法并且把 MapSubscriber 传入作为参数,并且调用它的 onNext 方法,因为 MapSubscriber 的生成是通过原 Subscriber 与 Func1 实现的,所以在 MapSubscriber 里面会拿到原 Observable.OnSubscribe 传入的数据流然后调用 Func1 进行转换然后再把转换结果作为参数继续调用原 Subscriber 的 onNext 方法,这样一来数据流到监听者那端就是被处理过的数据流了。(注:OnSubscribeLift 实现了 OnSubscribe,也就是可以作为OnSubscribe)

提问:为什么会生成新的 Observable 与 Observable.OnSubscribe (OnSubscribeLift) 与 Subscriber(MapSubscriber) ?

因为被监听者到监听者的数据流方式要被打断,中间要加入一环,所以生成一个新的 Observable 与 Observable.OnSubscribe(OnSubscribeLift) ,这个里面还要保存原 Observable.OnSubscribe 的方法作为数据流的源头,然后还要生成一个新的 Subscriber (MapSubscriber),OnSubscribeLift 作为原数据流(也就是程序最开始执行的call方法)与 MapSubscriber 的桥接,而 MapSubscriber 里面执行了Map转换函数然后再继续执行与订阅者的调用。

好了Map函数说完了,应该通俗易懂比较好理解了吧,下面再来看看 flatMap函数:

可以提前给大家介绍下flatMap函数与Map函数的区别,Map函数起的作用是转换数据流的数据,然后往下再传递,flatMap其实也有类似的效果也是可以处理数据流的数据(为什么这么说,咋们往下看),只不过是Map函数里面call方法直接返回转换的数据类型,而flatMap返回的是一个Observable对象

下面我们看看flatMap的基本使用,老规矩上一个最基本的例子:

public void testFlatMap1(){
Observable observable = Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
Log.d("Rxjava", "onNext123");
subscriber.onNext("123");
}
});
observable.flatMap(new Func1>() {
@Override
public Observable call(String s) {
return createIpObservable(s);
}
})
.subscribe(new Action1() {
@Override
public void call(String s) {
Log.d("Rxjava", "Data: " + s);
}
});
}
private Observable createIpObservable(final String url)
{
return Observable.create(new Observable.OnSubscribe()
{
@Override
public void call(Subscriber super String> subscriber)
{
try {
String ip = url + "!!!";
Log.d("Rxjava", "Emit Data -> " + url);
subscriber.onNext(ip);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

打印为:

2020-05-04 00:35:25.819 4340-4340/com.example.myrxjava2 D/Rxjava: onNext123
2020-05-04 00:39:12.642 4340-4340/com.example.myrxjava2 D/Rxjava: Emit Data -> 123
2020-05-04 00:39:55.588 4340-4340/com.example.myrxjava2 D/Rxjava: Data: 123!!!

我们再来看看flatMap函数里面做了什么:

public final Observable flatMap(Func1 super T, ? extends Observable extends R>> func) {
if (getClass() == ScalarSynchronousObservable.class) {
return ((ScalarSynchronousObservable)this).scalarFlatMap(func);
}
return merge(map(func)); //里面有一个map函数,难怪上面说和map很像
}

再看看merge里面做了什么:

public static Observable merge(Observable extends Observable extends T>> source) {
if (source.getClass() == ScalarSynchronousObservable.class) {
return ((ScalarSynchronousObservable)source).scalarFlatMap((Func1)UtilityFunctions.identity());
}
return source.lift(OperatorMerge.instance(false));
}

merge里面又调用了lift函数,为什么说又调用了,大家可以回头看看map函数也调用了lift函数,只不过两次的参数不同而已,map里面调用lift函数的参数是OperatorMap,而merge里面调用lift函数的参数是OperatorMerge

那么大家可以想一想调用流程:map函数调用lift生成的 Observable 里面通过new一个OnSubscribeLift来作为原数据流(也就是程序最开始执行的call方法)与 MapSubscriber 的桥接,而merge里面是再利用lift函数再次生成了一个新的 Observable 里面的new的OnSubscribeLift 则应该为map函数里面的OnSubscribeLift 与 OperatorMerge的桥接,(注:OnSubscribeLift 实现了 OnSubscribe,也就是可以作为OnSubscribe)

所以程序执行的大致流程应该是:先执行 OperatorMerge 里面的 call 方法,然后执行 MapSubscriber 里面的call 方法,然后执行到原数据流(也就是程序最开始执行的call方法)的call方法,然后到flapMap(也可以说是map里面,因为flapMap里面调用了map)里面的 Func1 的call 方法,最后根据上一步返回值为 Observable 再执行其的 call 方法,最后把数据流传到订阅者Subscriber的call方法里面

😎流程是不是这样的呢,让我去验证下:

subscribe执行以后首先执行的是OperatorMergel里面的 OnSubscribeLift 里面的call方法

public void call(Subscriber super R> o) {
try {
Subscriber super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
parent.call(st);
} catch (Throwable e) {
// localized capture of errors rather than it skipping all operators
// and ending up in the try/catch of the subscribe method which then
// prevents onErrorResumeNext and other similar approaches to error handling
Exceptions.throwIfFatal(e);
st.onError(e);
}
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// if the lift function failed all we can do is pass the error to the final Subscriber
// as we don't have the operator available to us
o.onError(e);
}
}

hook.onLift(operator) 返回的就是生成的 OperatorMerge,再执行里面的call方法:

public Subscriber> call(final Subscriber super T> child) {
MergeSubscriber subscriber = new MergeSubscriber(child, delayErrors, maxConcurrent);
MergeProducer producer = new MergeProducer(subscriber);
subscriber.producer = producer;
child.add(subscriber);
child.setProducer(producer);
return subscriber;
}

OperatorMerge 里面的call方法做了几个事情其中最重要的就是 new MergeSubscriber 生成了一个 MergeSubscriber

public MergeSubscriber(Subscriber super T> child, boolean delayErrors, int maxConcurrent) {
this.child = child;
this.delayErrors = delayErrors;
this.maxConcurrent = maxConcurrent;
this.nl = NotificationLite.instance();
this.innerGuard = new Object();
this.innerSubscribers = EMPTY;
if (maxConcurrent == Integer.MAX_VALUE) {
scalarEmissionLimit = Integer.MAX_VALUE;
request(Long.MAX_VALUE);
} else {
scalarEmissionLimit = Math.max(1, maxConcurrent >> 1);
request(maxConcurrent);
}
}

里面很重要的一步就是 this.child = child; 而这个child就是订阅者Subscriber,然后执行 parent.call(st); 这个 parent 就是 map函数里面返回的 OnSubscribeLift,首先执行里面的 Subscriber super T> st = hook.onLift(operator).call(o); 这个operator则应该是 MapSubscriber 执行他的call方法:

public Subscriber super T> call(final Subscriber super R> o) {

MapSubscriber parent = new MapSubscriber(o, transformer);

o.add(parent);

return parent;

}

返回一个 MapSubscriber ,再执行map 的OnSubscribeLift里面的parent.call(st);

这个里面的parent就是原数据流(也就是最开始要执行的call)函数:

Observable observable = Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
Log.d("Rxjava", "onNext");
subscriber.onNext("333");
}
});

这里面的 Subscriber 则应该为MapSubscriber,然后调用其 onNext 方法:

public void onNext(T t) {
R result;
try {
result = mapper.call(t);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
unsubscribe();
onError(OnErrorThrowable.addValueAsLastCause(ex, t));
return;
}
actual.onNext(result);
}

先用 result = mapper.call(t); ,mapper则为Fun1 ,也就是调用Fun1

里面的call方法:

new Func1>() {
@Override
public Observable call(String s) {
return createIpObservable(s);
}
}

这个方法返回的是一个新的 Observable 对象:

最后调用MapSubscriber 里面的 actual.onNext(result); 这个actual就是创建MapSubscriber传进来的 MergeSubscriber ,所以执行他的 onNext 方法:

public void onNext(Observable extends T> t) {
if (t == null) {
return;
}
if (t == Observable.empty()) {
emitEmpty();
} else
if (t instanceof ScalarSynchronousObservable) {
tryEmit(((ScalarSynchronousObservable extends T>)t).get());
} else {
InnerSubscriber inner = new InnerSubscriber(this, uniqueId++);
addInner(inner);
t.unsafeSubscribe(inner); //关键一句话
emit();
}
}

里面 t.unsafeSubscribe(inner);

public final Subscription unsafeSubscribe(Subscriber super T> subscriber) {
try {
// new Subscriber so onStart it
subscriber.onStart();
// allow the hook to intercept and/or decorate
hook.onSubscribeStart(this, onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);
} catch (Throwable e) {
return Subscriptions.unsubscribed();
}
}

这个里面的调用 hook.onSubscribeStart(this, onSubscribe).call(subscriber); 而这个里面的 onSubscribe 就是上面通过 createIpObservable 生成的 Observable ,执行他的call 方法 :

private Observable createIpObservable(final String url)
{
return Observable.create(new Observable.OnSubscribe()
{
@Override
public void call(Subscriber super String> subscriber)
{
try {
String ip = url + "!!!";
Log.d("Rxjava", "Emit Data -> " + url);
subscriber.onNext(ip);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

里面处理完数据流以后会调用 subscriber.onNext(ip); 这个里面的 subscriber 就是上面new出来的InnerSubscriber,再调用其onNext 方法:

public void onNext(T t) {
parent.tryEmit(this, t);
}
parent 就是 OperatorMerge,接着调用tryEmit:
void tryEmit(InnerSubscriber subscriber, T value) {
boolean success = false;
long r = producer.get();
if (r != 0L) {
synchronized (this) {
// if nobody is emitting and child has available requests
r = producer.get();
if (!emitting && r != 0L) {
emitting = true;
success = true;
}
}
}
if (success) {
emitScalar(subscriber, value, r);
} else {
queueScalar(subscriber, value);
}
}

里面 emitScalar :

protected void emitScalar(InnerSubscriber subscriber, T value, long r) {
boolean skipFinal = false;
try {
try {
child.onNext(value);
} catch (Throwable t) {
//省略无关紧要的
}
}

而这个child 就是上面我们提到过的专门保存的订阅者也就是监听者subscriber,最后调用其onNext方法:(我们上文讲解了onNext 与 call 方法的联系,忘记了可以拉到上面进行查看),完成所有调用。

new Action1() {
@Override
public void call(String s) {
Log.d("Rxjava", "Data: " + s);
}
}

上面我是为了讲解flatMap的基础调用方式做的例子,一般情况下我们不会这么去使用flatMap,给大家一个例子参考:

public void testFlatMap(){
Observable observable = Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
Log.d("Rxjava", "onNext");
subscriber.onNext("1,2,3");
}
});
observable.flatMap(new Func1>() {
@Override
public Observable call(String s) {
String[] names = s.split(",");
return Observable.from(names);
}
}).subscribe(new Action1() {
@Override
public void call(String s) {
Log.d("Rxjava", "Consume Data 
}
});
}

打印:

2020-05-04 16:30:27.061 6627-6627/? D/Rxjava: onNext
2020-05-04 16:30:27.086 6627-6627/? D/Rxjava: Consume Data 
2020-05-04 16:30:27.086 6627-6627/? D/Rxjava: Consume Data 
2020-05-04 16:30:27.086 6627-6627/? D/Rxjava: Consume Data

我们最后来总结下:flatMap的调用也用到了map函数,只不过是Map函数里面call方法直接返回转换的数据类型,而flatMap返回的是一个Observable对象,其本质还是作为数据流的其中一环用于转换数据而出现的。