RxJava源码解析04-变换过程(flatmap)

flatmap

public final <R> Observable<R> flatMap(Func1<? super T, ? extends Observable<? extends R>> func) {
    //...
    return merge(map(func));
}  

在flatmap中,首先会调用map()将func转换为Observable类型,由于这里传入的泛型是Observable<? extends R>>,故会返回Observable<Observable<? extends R>>>类型,具体的转换在上一篇文章上已经讲过了。

获得Observable<Observable<? extends R>>>后,会调用merge(),来看下merge操作符的定义

将多个Observables的输出合并,就好像它们是一个单个的Observable一样。  

所以这里也就是把原来的Observable和map()新生成的Observable进行合并,从而生成新的Observable。

直接来看merge的核心代码

//Observable类
public static <T> Observable<T> merge(Observable<? extends Observable<? extends T>> source) {
    //...
    return source.lift(OperatorMerge.<T>instance(false));
}

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

可以看到lift()传参的时候,调用了OperatorMerge.<T>instance(false),这个最终会返回OperatorMerge实例。
这个类我们之后再来看。

再回到Observable#lift()

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

这里会把传入onSubscribe和operator生成一个OnSubscribeLift 。OnSubscribeLift 会把数据先交由operator#call()调用后,再给onSubscribe调用,这个我们上一篇文章中已经知道了。

最终通过unsafeCreate返回一个新的Observable。

主要逻辑在operator#call()

    public final class OperatorMerge<T> implements Operator<T, Observable<? extends T>> {
    @Override
    public Subscriber<Observable<? extends T>> call(final Subscriber<? super T> child) {
        MergeSubscriber<T> subscriber = new MergeSubscriber<T>(child, delayErrors, maxConcurrent);
        MergeProducer<T> producer = new MergeProducer<T>(subscriber);
        subscriber.producer = producer;

        child.add(subscriber);
        child.setProducer(producer);

        return subscriber;
    }

    //...
}  

call方法这里会创建一个MergeSubscriber,并且会调用setProducer()

public void setProducer(Producer p) {
    //...
    if (toRequest == NOT_SET) {
        producer.request(Long.MAX_VALUE);
    } else {
        producer.request(toRequest);
    }
}  

即调用MergeProducer的request()

 public void request(long n) {
        if (n > 0) {
            if (get() == Long.MAX_VALUE) {
                return;
            }
            BackpressureUtils.getAndAddRequest(this, n);
            subscriber.emit();
        } else if (n < 0) {
            throw new IllegalArgumentException("n >= 0 required");
        }
    }  

可以看到,最终调用了MergeSubscriber的emit()。emit会从queue中不断获取数据t并传给Subscriber child去执行。从而把Observable的数据逐个交给Subscriber的OnNext、onCompleted、onError进行调用。

 void emitLoop() {
        boolean skipFinal = false;
        try {
            final Subscriber<? super T> child = this.child;
            for (;;) {
                // eagerly check if child unsubscribed or we reached a terminal state.
                if (checkTerminate()) {
                    skipFinal = true;
                    return;
                }
                Queue<Object> svq = queue;

                long r = producer.get();
                boolean unbounded = r == Long.MAX_VALUE;

                // count the number of 'completed' sources to replenish them in batches
                int replenishMain = 0;

                // try emitting as many scalars as possible
                if (svq != null) {
                    for (;;) {
                        int scalarEmission = 0;
                        Object o = null;
                        while (r > 0) {
                            o = svq.poll();
                            // eagerly check if child unsubscribed or we reached a terminal state.
                            if (checkTerminate()) {
                                skipFinal = true;
                                return;
                            }
                            if (o == null) {
                                break;
                            }
                            T v = NotificationLite.getValue(o);
                            // if child throws, report bounce it back immediately
                            try {
                                child.onNext(v);
                            } catch (Throwable t) {
                                if (!delayErrors) {
                                    Exceptions.throwIfFatal(t);
                                    skipFinal = true;
                                    unsubscribe();
                                    child.onError(t);
                                    return;
                                }
                                getOrCreateErrorQueue().offer(t);
                            }
                            replenishMain++;
                            scalarEmission++;
                            r--;
                        }
                        if (scalarEmission > 0) {
                            if (unbounded) {
                                r = Long.MAX_VALUE;
                            } else {
                                r = producer.produced(scalarEmission);
                            }
                        }
                        if (r == 0L || o == null) {
                            break;
                        }
                    }
                }

                /*
                 * We need to read done before innerSubscribers because innerSubscribers are added
                 * before done is set to true. If it were the other way around, we could read an empty
                 * innerSubscribers, get paused and then read a done flag but an async producer
                 * might have added more subscribers between the two.
                 */
                boolean d = done;
                // re-read svq because it could have been created
                // asynchronously just before done was set to true.
                svq = queue;
                // read the current set of inner subscribers
                InnerSubscriber<?>[] inner = innerSubscribers;
                int n = inner.length;

                // check if upstream is done, there are no scalar values
                // and no active inner subscriptions
                if (d && (svq == null || svq.isEmpty()) && n == 0) {
                    Queue<Throwable> e = errors;
                    if (e == null || e.isEmpty()) {
                        child.onCompleted();
                    } else {
                        reportError();
                    }
                    skipFinal = true;
                    return;
                }

                boolean innerCompleted = false;
                if (n > 0) {
                    // let's continue the round-robin emission from last location
                    long startId = lastId;
                    int index = lastIndex;

                    // in case there were changes in the array or the index
                    // no longer points to the inner with the cached id
                    if (n <= index || inner[index].id != startId) {
                        if (n <= index) {
                            index = 0;
                        }
                        // try locating the inner with the cached index
                        int j = index;
                        for (int i = 0; i < n; i++) {
                            if (inner[j].id == startId) {
                                break;
                            }
                            // wrap around in round-robin fashion
                            j++;
                            if (j == n) {
                                j = 0;
                            }
                        }
                        // if we found it again, j will point to it
                        // otherwise, we continue with the replacement at j
                        index = j;
                        lastIndex = j;
                        lastId = inner[j].id;
                    }

                    int j = index;
                    // loop through all sources once to avoid delaying any new sources too much
                    for (int i = 0; i < n; i++) {
                        // eagerly check if child unsubscribed or we reached a terminal state.
                        if (checkTerminate()) {
                            skipFinal = true;
                            return;
                        }
                        @SuppressWarnings("unchecked")
                        InnerSubscriber<T> is = (InnerSubscriber<T>)inner[j];

                        Object o = null;
                        for (;;) {
                            int produced = 0;
                            while (r > 0) {
                                // eagerly check if child unsubscribed or we reached a terminal state.
                                if (checkTerminate()) {
                                    skipFinal = true;
                                    return;
                                }
                                RxRingBuffer q = is.queue;
                                if (q == null) {
                                    break;
                                }
                                o = q.poll();
                                if (o == null) {
                                    break;
                                }
                                T v = NotificationLite.getValue(o);
                                // if child throws, report bounce it back immediately
                                try {
                                    child.onNext(v);
                                } catch (Throwable t) {
                                    skipFinal = true;
                                    Exceptions.throwIfFatal(t);
                                    try {
                                        child.onError(t);
                                    } finally {
                                        unsubscribe();
                                    }
                                    return;
                                }
                                r--;
                                produced++;
                            }
                            if (produced > 0) {
                                if (!unbounded) {
                                    r = producer.produced(produced);
                                } else {
                                    r = Long.MAX_VALUE;
                                }
                                is.requestMore(produced);
                            }
                            // if we run out of requests or queued values, break
                            if (r == 0 || o == null) {
                                break;
                            }
                        }
                        boolean innerDone = is.done;
                        RxRingBuffer innerQueue = is.queue;
                        if (innerDone && (innerQueue == null || innerQueue.isEmpty())) {
                            removeInner(is);
                            if (checkTerminate()) {
                                skipFinal = true;
                                return;
                            }
                            replenishMain++;
                            innerCompleted = true;
                        }
                        // if we run out of requests, don't try the other sources
                        if (r == 0) {
                            break;
                        }

                        // wrap around in round-robin fashion
                        j++;
                        if (j == n) {
                            j = 0;
                        }
                    }
                    // if we run out of requests or just completed a round, save the index and id
                    lastIndex = j;
                    lastId = inner[j].id;
                }

                if (replenishMain > 0) {
                    request(replenishMain);
                }
                // if one or more inner completed, loop again to see if we can terminate the whole stream
                if (innerCompleted) {
                    continue;
                }
                // in case there were updates to the state, we loop again
                synchronized (this) {
                    if (!missed) {
                        skipFinal = true;
                        emitting = false;
                        break;
                    }
                    missed = false;
                }
            }
        } finally {
            if (!skipFinal) {
                synchronized (this) {
                    emitting = false;
                }
            }
        }
    }

至此,完成了flatmap变换过程的解析。

总结

flatmap的变换实际上就是先通过map()将Fun1转换为Observable< Observable<T>>,再交由merge()将两个Observable合并,生成新的Observable。当执行时,内部会通过不断获取队列的数据,再交由Subscriber进行OnNext、onCompleted、onError的调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RxJava中的flatMap操作符是一个非常常用的操作符,它可以将一个Observable发射的事件序列转换成多个Observables,然后将这些Observables发射的事件序列合并后再发射出去。 下面是flatMap操作符的源码解析: ```java public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) { ObjectHelper.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableFlatMap<>(this, mapper, false, Integer.MAX_VALUE, bufferSize())); } ``` 可以看到,flatMap操作符的实现是通过创建一个ObservableFlatMap对象来完成的。其中,mapper参数表示将原始Observable发射的事件转换成的新Observable,它是一个Function类型的参数,即接受一个T类型的参数并返回一个ObservableSource类型的结果。 ObservableFlatMap的构造函数如下所示: ```java ObservableFlatMap(ObservableSource<T> source, Function<? super T, ? extends ObservableSource<? extends R>> mapper, boolean delayErrors, int maxConcurrency, int bufferSize) { this.source = source; this.mapper = mapper; this.delayErrors = delayErrors; this.maxConcurrency = maxConcurrency; this.bufferSize = bufferSize; } ``` ObservableFlatMap的核心实现是在subscribeActual方法中完成的: ```java @Override public void subscribeActual(Observer<? super R> observer) { if (ObservableScalarXMap.tryScalarXMapSubscribe(source, observer, mapper)) { return; } source.subscribe(new FlatMapObserver<>(observer, mapper, delayErrors, maxConcurrency, bufferSize)); } ``` 在subscribeActual方法中,首先判断源Observable是否可以直接转换为ObservableScalarXMap,如果可以的话直接进行转换,否则创建一个FlatMapObserver对象并进行订阅。 FlatMapObserver是flatMap的核心实现类,它实现了Observer接口,并且在接收到源Observable发射的事件时,会先将事件转换成新的Observable,然后将新Observable的发射事件序列合并到一个新的Observable中,最后再将新的Observable发射出去。 ```java static final class FlatMapObserver<T, R> extends AtomicInteger implements Observer<T>, Disposable { // ... @Override public void onNext(T t) { ObservableSource<? extends R> o; try { o = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper returned a null ObservableSource"); } catch (Throwable e) { Exceptions.throwIfFatal(e); upstream.dispose(); onError(e); return; } if (cancelled) { return; } if (maxConcurrency != Integer.MAX_VALUE) { synchronized (this) { if (wip == maxConcurrency) { queue.offer(t); return; } wip++; } } o.subscribe(new InnerObserver(inner, delayErrors, this)); } // ... } ``` 在FlatMapObserver的onNext方法中,首先调用mapper将源Observable发射的事件转换成新的Observable,并进行非空检查。然后判断当前的并发度是否达到了最大值,如果达到了最大值,就将源Observable发射的事件放到队列中。否则,就将并发度加1,并订阅新Observable。 InnerObserver是FlatMapObserver的内部类,它实现了Observer接口,并在接收到来自新Observable的发射事件序列时,将它们合并到一个新的Observable中,并将新的Observable发射出去。 ```java static final class InnerObserver<R> implements Observer<R> { // ... @Override public void onNext(R t) { if (done) { return; } inner.onNext(t); } // ... } ``` 当所有的新Observable都完成后,FlatMapObserver会调用onComplete方法通知观察者。如果发生了异常,FlatMapObserver会调用onError方法通知观察者。同时,FlatMapObserver还实现了Disposable接口,可以通过dispose方法取消订阅。 综上所述,flatMap操作符的实现是比较复杂的,它通过创建ObservableFlatMap对象,并在subscribeActual方法中创建FlatMapObserver对象来完成转换操作。在FlatMapObserver中,它还需要实现对新Observable的订阅以及将新Observable发射的事件合并到一个新的Observable中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

氦客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值