RxJava源码阅读理解系列(五)

  • 操作符
  • concatMap
  • groupBy


操作符

今天我们继续来阅读RxJava中常用的操作符的源码。

concatMap

concatMap和flatMap基本功能类似,区别在于concatMap接收到的数据源顺序是有序的而flatMap是无序的。
因为在flatMap中,订阅操作订阅MergeObserver的时候并发地创建了多个InnerObserver并存储在了ArrayDeque这个非线程安全的数据结构中,而concatMap中并没有这个操作,只有一个SourceObserver中用队列存储了上游的数据源,因此能保证数据的顺序。整个操作流程和flatMap如出一辙,就不多做分析了。

groupBy

rxjava 理解mvvm rxjava concatmap_操作符


groupBy的官方文档说明是这样:把一个被观察者分成多个被观察者,每个被观察者发射原始被观察者中发射数据的一个子集。

我们来看一下用法:

Observable<String> animals = Observable.just(
    "Tiger", "Elephant", "Cat", "Chameleon", "Frog", "Fish", "Turtle", "Flamingo");

animals.groupBy(animal -> animal.charAt(0), String::toUpperCase)
    .concatMapSingle(Observable::toList)
    .subscribe(System.out::println);

// prints:
// [TIGER, TURTLE]
// [ELEPHANT]
// [CAT, CHAMELEON]
// [FROG, FISH, FLAMINGO]

我们可以看到上面的例子,我们成功地把所有首字母一样的数据源归为了一类。接下来上代码:

@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <K, V> Observable<GroupedObservable<K, V>> groupBy(Function<? super T, ? extends K> keySelector,
        Function<? super T, ? extends V> valueSelector) {
    return groupBy(keySelector, valueSelector, false, bufferSize());
}

@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <K, V> Observable<GroupedObservable<K, V>> groupBy(Function<? super T, ? extends K> keySelector,
        Function<? super T, ? extends V> valueSelector,
        boolean delayError, int bufferSize) {
    ObjectHelper.requireNonNull(keySelector, "keySelector is null");
    ObjectHelper.requireNonNull(valueSelector, "valueSelector is null");
    ObjectHelper.verifyPositive(bufferSize, "bufferSize");

    return RxJavaPlugins.onAssembly(new ObservableGroupBy<T, K, V>(this, keySelector, valueSelector, bufferSize, delayError));
}

我们看到ObservableGroupBy的subscribeActual

@Override
public void subscribeActual(Observer<? super GroupedObservable<K, V>> t) {
    source.subscribe(new GroupByObserver<T, K, V>(t, keySelector, valueSelector, bufferSize, delayError));
}

继续看GroupByObserver的onNext():

@Override
public void onNext(T t) {
    K key;
    try {
        key = keySelector.apply(t);
    } catch (Throwable e) {
        Exceptions.throwIfFatal(e);
        upstream.dispose();
        onError(e);
        return;
    }

    Object mapKey = key != null ? key : NULL_KEY;
    GroupedUnicast<K, V> 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();

        downstream.onNext(group);
    }

    V v;
    try {
        v = ObjectHelper.requireNonNull(valueSelector.apply(t), "The value supplied is null");
    } catch (Throwable e) {
        Exceptions.throwIfFatal(e);
        upstream.dispose();
        onError(e);
        return;
    }

    group.onNext(v);
}

这里就是核心的处理逻辑了:
首先通过keySelector生成key,在我们上面的例子中,是取出字符串的首字母,所以这里的key是所有字符串的首字母。这里我们知道生成的组是保存在了ConcurrentHashMap中:

this.groups = new ConcurrentHashMap<Object, GroupedUnicast<K, V>>();

接着我们从这个map中根据生成的key取分组后的Observable,也就是这里的GroupedUnicast,如果还没有,我们就根据这个key取创建一个并把他们保存到map中,接着把这个GroupedUnicast发到我们的观察者中。
紧接着通过valueSelector转换了我们的数据源,并把转换后的数据源传入了GroupedUnicast的onNext()方法:

public void onNext(T t) {
    state.onNext(t);
}

这里调用了state的onNext()方法,这里的state是我们在创建GroupedUnicast的时候创建的,从名字上看他应该是保存了GroupedUnicast的状态,我们看到他的onNext()方法:

public void onNext(T t) {
    queue.offer(t);
    drain();
}

我们看到这边先把数据丢到了队列中,然后又是调用了这个熟悉的drain()方法:

void drain() {
    if (getAndIncrement() != 0) {
        return;
    }
    int missed = 1;

    final SpscLinkedArrayQueue<T> q = queue;
    final boolean delayError = this.delayError;
    Observer<? super T> a = actual.get();
    for (;;) {
        if (a != null) {
            for (;;) {
                boolean d = done;
                T v = q.poll();
                boolean empty = v == null;

                if (checkTerminated(d, empty, a, delayError)) {
                    return;
                }

                if (empty) {
                    break;
                }

                a.onNext(v);
            }
        }

        missed = addAndGet(-missed);
        if (missed == 0) {
            break;
        }
        if (a == null) {
            a = actual.get();
        }
    }
}

这里也都是一些算法的实现,主要的工作就是取出队列中所有的数据并都发送到观察者中。
所以最终的逻辑总结下来就是根据key把所有数据分成多个组,每个组被包装成了一个Observable,外层的Observable发射出这些包装后的Observable,包装过的Observable再发射出这个组中的所有数据。
结束语
今天的分析就先到这里,我们今天又分析了一个比较复杂的操作符。我们应该可以发现,复杂一些的操作符对数据结构和算法还是需要有一定的基础的,所以建议大家有空的时候多研究研究常用的数据结构和算法,这样才能设计出强大的软件。