作者: 一字马胡
转载标志 【2017-12-15】
更新日志
日期 | 更新内容 | 备注 |
---|---|---|
2017-12-15 | RxJava学习笔记系列 | 系列笔记 (二) |
2017-12-15 | RxJava 学习笔记 (一) | 增加系列笔记一 |
2017-12-15 21:36 | 考虑到RxJava很大程度上用于android开发中,而我自身不是移动开发者,所以暂时将RxJava学习笔记系列挂起,在未来需要使用RxJava的时候再继续学习,并且结合实际的应用来学习会收获更多 | 挂起 |
导入
在RxJava学习笔记系列的第一篇文章中,我分析了RxJava中核心的两个对象Observable和Observer,并且分析了Observer是如何实现订阅一个Observable的,作为学习RxJava的第一篇分析总结,内容较为浅显,本文将接着RxJava 学习笔记 (一),重点在于学习RxJava的Observable提供的丰富的数据流聚合操作api。
在学习RxJava Observable的聚合操作之前,可以结合java 8中的Stream API来学习,可以参考Java Streams API,两者之间是互通的。
介于RxJava提供了大量的聚合操作api,本文将挑选其中几个比较有代表性的api进行分析总结,其余的api可以参考RxJava的源代码,以及结合自身实践来学习。
count
count操作用来获取Observable在触发onComplete的时候一共发送了多少个数据项,具体可以看下面的解释:
Returns a Single that counts the total number of items
emitted by the source ObservableSource and emits this
count as a 64-bit Long.
下面是一个使用count操作的例子:
Observable observable = Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("test1");
e.onNext("test2");
e.onComplete();
}
});
observable.subscribe(new Consumer() {
public void accept(String s) throws Exception {
System.out.println("->" + s);
}
});
observable.count().subscribe(new Consumer() {
public void accept(Long aLong) throws Exception {
System.out.println("total emit:" + aLong);
}
});
最后count的输出是2,也就是说Observable在触发onComplete的时候一共发送了2个数据,需要注意的是,我们在完成发送数据之后需要及时调用Observer的onComplete方法来告诉Observer上游的Observable已经完成发送数据了,Observable在调用了Observer的onComplete方法之后,再调用onNext方法就发送不出去了,为什么呢?除了调用onComplete来结束Observer再接收到Observable的事件之外,调用onError也是同样的效果,下面就来分析一下为什么会这样。
在上面的代码中,我们的Observable是通过调用Observable的静态方法create来创建的,来具体看一下create的实现:
public static Observable create(ObservableOnSubscribe source) {
ObjectHelper.requireNonNull(source, "source is null");
return RxJavaPlugins.onAssembly(new ObservableCreate(source));
}
关于Observable和Observer是如何联系起来的,可以参考第一篇文章RxJava 学习笔记 (一),下面来看一下ObservableCreate类中是如何来调用Observer的onNext方法的,也就是来看看到底为什么Observable在调用了Observer的onComplete之后再调用onNext方法就不管用了,主要来看ObservableCreate类里面的CreateEmitter类的onNext方法,因为在ObservableCreate里面,Observer被转换为了CreateEmitter:
@Override
public void onNext(T t) {
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values
are generally not allowed in 2.x operators and sources."));
return;
}
if (!isDisposed()) {
observer.onNext(t);
}
}
首先判断了一下需要发送的事件是否为null,如果为null则直接抛出异常,否则会调用一个方法isDisposed来哦按段是否能调用实际的Observer的onNext方法,下面是isDisposed方法的具体实现细节:
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
/**
* Checks if the given Disposable is the common {@link #DISPOSED} enum value.
* @param d the disposable to check
* @return true if d is {@link #DISPOSED}
*/
public static boolean isDisposed(Disposable d) {
return d == DISPOSED;
}
Disposable在RxJava中是一个重要的对象,它可以用来取消订阅关系,并且支持查询是否已经取消订阅的状态,isDisposed方法最终需要判断当前Observer的Disposable是否等于DISPOSED,如果是,那么就是出于已经取消订阅的状态,那么就不需要继续调用Observer的onNext方法来传播事件了,否则继续调用,那么这个状态是在哪里更新的呢?可以在onComplete和onError中看到状态的更新:
首先来看onError:
public void onError(Throwable t) {
if (!tryOnError(t)) {
RxJavaPlugins.onError(t);
}
}
public boolean tryOnError(Throwable t) {
if (t == null) {
t = new NullPointerException("onError called with null. Null
values are generally not allowed in 2.x operators and sources.");
}
if (!isDisposed()) {
try {
observer.onError(t);
} finally {
dispose();
}
return true;
}
return false;
}
其中重点在于dispose方法:
@Override
public void dispose() {
DisposableHelper.dispose(this);
}
/**
* Atomically disposes the Disposable in the field if not already disposed.
* @param field the target field
* @return true if the current thread managed to dispose the Disposable
*/
public static boolean dispose(AtomicReference field) {
Disposable current = field.get();
Disposable d = DISPOSED;
if (current != d) {
current = field.getAndSet(d);
if (current != d) {
if (current != null) {
current.dispose();
}
return true;
}
}
return false;
}
可以看到,Observer的Disposable就是在dispose方法里面被更新为DISPOSED的。下面再来看onComplete:
@Override
public void onComplete() {
if (!isDisposed()) {
try {
observer.onComplete();
} finally {
dispose();
}
}
}
可以看到,也会调用dispose方法来更新Observer的Dispose的状态。
first/last
使用first/last操作可以获取Observable发送给Observer的第一个事件和最后一个事件,下面是简单的使用示例:
Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("test1");
e.onNext("test2");
e.onComplete();
}
})./*first("default")*/last("default").subscribe(new Consumer() {
public void accept(String s) throws Exception {
System.out.println(s);
}
});
下面来简单分析一下first/last的实现原理,为了不赘述,拿last的实现来分析,last的方法实现细节如下:
public final Single last(T defaultItem) {
ObjectHelper.requireNonNull(defaultItem, "defaultItem is null");
return RxJavaPlugins.onAssembly(new ObservableLastSingle(this, defaultItem));
}
该方法会返回一个ObservableLastSingle对象,ObservableLastSingle是一种特殊的Observable,它只能发射一条数据。并且继续跟进看会发现订阅该Observable的Observer会被包装成一个LastObserver。神奇的地方在于,SingleObserver没有onNext,所以LastObserver每次调用onNext都会记录下事件,当LastObserver调用了onComplete方法的时候,下面的代码展示了具体的实现细节:
@Override
public void onComplete() {
s = DisposableHelper.DISPOSED;
T v = item;
if (v != null) {
item = null;
actual.onSuccess(v);
} else {
v = defaultItem;
if (v != null) {
actual.onSuccess(v);
} else {
actual.onError(new NoSuchElementException());
}
}
}
actual就是last之后的Observer,所以这里可以看出来,会将Observable的最后一个事件通过onSuccess来告诉Observer。first的分析类似就不再赘述了。
map
map操作可以对Observable的每个事件进行转换,转换成一个其他的事件,再通知到Observer,下面是一个简单的使用map的示例:
Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("test1");
e.onNext("1001");
e.onComplete();
}
}).map(new Function() {
public Integer apply(String s) throws Exception {
try {
return Integer.parseInt(s);
} catch (NumberFormatException nbe) {
return 0;
}
}
}).subscribe(new Consumer() {
public void accept(Integer integer) throws Exception {
System.out.println("->" + integer);
}
});
我们是提供了一个Function来进行转换的,在上面的例子中实现的是将String类型的事件转换为Integer类型的事件,具体的实现还是比较简单的:
public final Observable map(Function super T, ? extends R> mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
return RxJavaPlugins.onAssembly(new ObservableMap(this, mapper));
}
可以看到,调用map操作涉及到一个新的包装类ObservableMap,在ObservableMap内部进行Observer绑定的时候,细节代码如下:
@Override
public void subscribeActual(Observer super U> t) {
source.subscribe(new MapObserver(t, function));
}
又出现了一个包装类MapObserver,并且将Observer和mapper function都包装起来了,来看一个MapObserver的onNext的实现细节:
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != NONE) {
actual.onNext(null);
return;
}
U v;
try {
v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper
function returned a null value.");
} catch (Throwable ex) {
fail(ex);
return;
}
actual.onNext(v);
}
可以看到,在进行Observer的onNext调用之前,会首先调用mapper.apply来进行事件转换,然后再将转换结果发送出去,很好理解。其他操作也可以根据这套逻辑进行分析,就不再赘述。
flatMap
flatMap和map类似,但是map是将单个事件进行转换,变成一个其他的事件,本质上还是事件,但是flatMap会将单个事件铺开成一个新的Observable,下面是一个使用flatMap的简单示例:
Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("test1");
e.onNext("1001");
e.onComplete();
}
}).flatMap(new Function>() {
public ObservableSource apply(final String s) throws Exception {
return Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
int result = 0;
try {
result = Integer.parseInt(s);
} catch (NumberFormatException nfe) {
result = 0;
}
e.onNext(result);
e.onComplete();
}
});
}
}).subscribe(new Consumer() {
public void accept(Integer integer) throws Exception {
System.out.println("->" + integer);
}
});
介于flatMap的分析有些繁琐,就不再此进行描述了,对于flatMap实现原理的分析,可以参考前面的map的分析,但是flatMap的实现确实比起map要复杂得多,下面给出onNext的分析路径,可以参考下面的路径来分析flatMap的具体实现:
1:
Observable:public final Observable flatMap(Function super T,
? extends ObservableSource extends R>> mapper, boolean delayErrors,
int maxConcurrency, int bufferSize)
2:
ObservableFlatMap:ublic void subscribeActual(Observer super U> t)
3:
MergeObserver:public void onNext(T t)
->void subscribeInner(ObservableSource extends U> p)
->void tryEmitScalar(Callable extends U> value)
"actual.onNext(u);"
filter
filter操作可以过滤调一些不需要的事件,Observer可以订阅自己关心的事件,下面是一个使用filter的简单示例:
Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("test1");
e.onNext("1001");
e.onComplete();
}
}).filter(new Predicate() {
public boolean test(String s) throws Exception {
return s.length() > 4;
}
}).subscribe(new Consumer() {
public void accept(String s) throws Exception {
System.out.println("->" + s);
}
});
关于filter的具体实现原理,参考map的实现,模式是一模一样的,只是map将一个事件转换为另外一个事件,而filter会对每个事件调用test方法来进行测试是否为Observer感兴趣,如果感兴趣则会返回true,那么该事件就可以通知到下游Observer,否则就是下游Observer不感兴趣的事件,就不会被通知到下游Observer。
reduce
reduce可以将多个事件合并为一个事件,一个比较形象的例子是,上游Observable发射一批整形数据,然后使用reduce操作进行求和操作,下游Observer就可以取到所有数的和,下面是一个简单的实现:
Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
for (int i = 0;i < 10; i ++) {
e.onNext(i);
}
e.onComplete();
}
}).reduce(new BiFunction() {
public Integer apply(Integer integer, Integer integer2) throws Exception {
return integer + integer2;
}
}).subscribe(new Consumer() {
public void accept(Integer integer) throws Exception {
System.out.println("sum:" + integer);
}
});
当然还可以使用reduce来求最大最小值,以及一些其他的具有比较性质、累计性质的操作。reduce的实现原理可以结合last和map的分析来理解,再次不再赘述。
toList/toMap
你可以将Observable发送的事件直接转换为一个list,或者是一个map,下面是使用toList的简单示例:
Observable.create(new ObservableOnSubscribe() {
public void subscribe(ObservableEmitter e) throws Exception {
for (int i = 0;i < 10; i ++) {
e.onNext(i);
}
e.onComplete();
}
}).toList().subscribe(new Consumer>() {
public void accept(List integers) throws Exception {
integers.forEach(new java.util.function.Consumer() {
@Override
public void accept(Integer integer) {
System.out.print(integer + " ");
}
});
}
});
下面来分析一下toList的具体实现:
public final Single> toList(final int capacityHint) {
ObjectHelper.verifyPositive(capacityHint, "capacityHint");
return RxJavaPlugins.onAssembly(new ObservableToListSingle>(this, capacityHint));
}
可以看到toList返回的是一个ObservableToListSingle类型的Observable,来看一下ObservableToListSingle里面的subscribeActual方法的具体实现(至于为什么要看这个方法,可以参考系列文章的第一篇):
@Override
public void subscribeActual(SingleObserver super U> t) {
U coll;
try {
coll = ObjectHelper.requireNonNull(collectionSupplier.call(), "The
collectionSupplier returned a null collection. Null values are
generally not allowed in 2.x operators and sources.");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
EmptyDisposable.error(e, t);
return;
}
source.subscribe(new ToListObserver(t, coll));
}
可以看到将Observer转换为了一个ToListObserver,下面来看一下我们比较关系的onNext方法的实现:
@Override
public void onNext(T t) {
collection.add(t);
}
看起来onNext的作用就是拦截Observable的事件,然后保存起来,那猜测应该会在onComplete的时候将这个List发送给下游Observe,下面来看一下onComplete的具体实现:
@Override
public void onComplete() {
U c = collection;
collection = null;
actual.onSuccess(c);
}
和猜测的一样,toMap操作的分析类似于toList,并且我们可以猜测toMap操作需要我们提供一个转换function,然后toMap会在实际实现中和toList一样拦截上游Observable的事件,然后调用我们提供的function来进行转换为一个Map的Entry,最后在onComplete的时候将整个map发送到下游Observer,具体的分析就不再此赘述了。
groupBy
下面来分析最后一个操作groupBy,也就是分组,可以对Observable的事件进行分组,然后按照组别来将事件组传递到下游Observer中去,下面是一个简单的使用groupBy的例子:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("hujian1");
e.onNext("hujian2");
e.onNext("libai1");
e.onNext("libai2");
e.onComplete();
}
}).groupBy(new Function() {
@Override
public String apply(String s) throws Exception {
return s.substring(0, s.length() - 1);
}
}).subscribe(new Consumer>() {
@Override
public void accept(GroupedObservable stringStringGroupedObservable) throws Exception {
System.out.println("group key:" + stringStringGroupedObservable.getKey());
stringStringGroupedObservable.subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
System.out.println(s);
}
});
}
});
下面来看一下groupBy的关键实现代码:
@Override
public void subscribeActual(Observer super GroupedObservable> t) {
source.subscribe(new GroupByObserver(t, keySelector, valueSelector,
bufferSize, delayError));
}
@Override
public void onNext(T t) {
K key;
try {
key = keySelector.apply(t);
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
s.dispose();
onError(e);
return;
}
Object mapKey = key != null ? key : NULL_KEY;
GroupedUnicast group = groups.get(mapKey);
if (group == null) {
// if the main has been cancelled, stop creating groups
// and skip this value
if (cancelled.get()) {
return;
}
group = GroupedUnicast.createWith(key, bufferSize, this, delayError);
groups.put(mapKey, group);
getAndIncrement();
actual.onNext(group);
}
V v;
try {
v = ObjectHelper.requireNonNull(valueSelector.apply(t),
"The value supplied is null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
s.dispose();
onError(e);
return;
}
group.onNext(v);
}
实现的就是按照我们的keySelect来进行分组的功能,可以从onNext的实现中发现,groupBy在发现一个新的key的时候就会调用下游Observer的onNext,而不是等Observable所有事件发送结束后再一次性发送结果,这一点需要特别注意。
本文到此就结束了,文章介绍了几个较为典型的RxJava Observable提供的聚合操作,并且每个操作都有例子进行分析,以及每一个操作的具体实现细节的分析总结,当然RxJava中Observable提供的聚合操作时非常丰富的,本文提到的只是冰山一角,其他的操作还需要自己多进行实践总结。
注:文章中的图片参考:projectreactor.io