啃源码-(RxJava事件流的变换操作)

309 阅读4分钟

在上一篇文章啃源码 - RxJava(事件流的创建与接收)分析了RxJava中的事件创建与接收,上一篇我们偶然发现一个抽象的类AbstractObservableWithUpstream,我们的猜测是类似于map以及flatmap这些都操作符,是对上游事件源进行包裹、变化等相关操作那我们点到AbstractObservableWithUpstream里面看看

abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> implements HasUpstreamObservableSource<T> {

    /** The source consumable Observable. */
    protected final ObservableSource<T> source;

    /**
     * Constructs the ObservableSource with the given consumable.
     * @param source the consumable Observable
     */
    AbstractObservableWithUpstream(ObservableSource<T> source) {
        this.source = source;
    }

    @Override
    public final ObservableSource<T> source() {
        return source;
    }
}

这个类接收了一个source的事件流,并实现了HasUpstreamObservableSource里面的source方法返回了包裹的source,我们看一下AbstractObservableWithUpstream的继承关系,ObservableTakeLast、ObservableDelay、ObservableMap、ObservableFlatMap等等,不知道大家有没有发现一个规律,这些类的命名与我们用到的操作符都很像,带着这个疑问那我们索性就去看一看Observable里面的map方法

public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
    ObjectHelper.requireNonNull(mapper, "mapper is null");
    return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}

恩,跟我们想的一样,返回了一个ObservableMap,那我们是不是可以猜测那个以操作符命名的Observable都与该操作符对应?我们也看看flatMap方法

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方法的调用,最终我们发现调用到此重载方法,在前面判断了一下是否是ScalarCallable,经过判断来返回empty的Observable或者 ObservableScalarXMap,如果不是ScalarCallable的话,直接就返回ObservableFlatMap,那我们先看看ObservableMap里面

public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
    super(source);
    this.function = function;
}

@Override
public void subscribeActual(Observer<? super U> t) {
    source.subscribe(new MapObserver<T, U>(t, function));
}

在subscribeActual里面直接调用了source的subscribe方法,并传递了一个MapObserver,点进去

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);
}

可以看到对事件t应用了mapper方法,再调用用actual的onNext方法,此处的actual就是我们传递进来的Observer,恩,原来map操作就是对事件运用了mapper的方法再进行发送。 RxJava中的操作符有很多,我们经常用到的线程切换也是通过类似操作符来完成的,我们一起来看一下subscribeOn

public final Observable<T> subscribeOn(Scheduler scheduler) {
    ObjectHelper.requireNonNull(scheduler, "scheduler is null");
    return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}

返回了一个ObservableSubscribeOn,继续跟进去看看

public void subscribeActual(final Observer<? super T> s) {
    final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);

    s.onSubscribe(parent);

    parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}

不对劲!subscribeActual里面只调用了observer的onSubscribe方法,我们之前看到的其他的observable中都会去调用source的subscribe方法,我们先继续看,SubscribeTask

final class SubscribeTask implements Runnable {
    private final SubscribeOnObserver<T> parent;

    SubscribeTask(SubscribeOnObserver<T> parent) {
        this.parent = parent;
    }

    @Override
    public void run() {
        source.subscribe(parent);
    }
}

哦,原来他把订阅的调用转变成了一个Runnable了,scheduler.scheduleDirect(new SubscribeTask(parent),scheduler是我们传进来了scheduler,这里我们用IoScheduler来分析,看IoScheduler的scheduleDirect方法

public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
    if (tasks.isDisposed()) {
        // don't schedule, we are unsubscribed
        return EmptyDisposable.INSTANCE;
    }

    return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}

继续看ThreadWorder的scheduleActual方法

public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
    Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

    ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);

    if (parent != null) {
        if (!parent.add(sr)) {
            return sr;
        }
    }

    Future<?> f;
    try {
        if (delayTime <= 0) {
            f = executor.submit((Callable<Object>)sr);
        } else {
            f = executor.schedule((Callable<Object>)sr, delayTime, unit);
        }
        sr.setFuture(f);
    } catch (RejectedExecutionException ex) {
        if (parent != null) {
            parent.remove(sr);
        }
        RxJavaPlugins.onError(ex);
    }

    return sr;
}

上面对我们的Runnable进行了包装,最后还是通过executor来执行任务完成订阅操作以及线程的切换 趁热打铁,我们继续看一下另外一个线程切换的方法observeOn,都是一样的规律,返回了一个ObservableObserveOn,继续点进去

protected void subscribeActual(Observer<? super T> observer) {
    if (scheduler instanceof TrampolineScheduler) {
        source.subscribe(observer);
    } else {
        Scheduler.Worker w = scheduler.createWorker();

        source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
    }
}

第一步判断是不是在同一个线程中执行,如果是直接订阅,如果线程不同,就专门创建了ObserveOnObserver,我们看看ObserveOnObserver里面

public void onNext(T t) {
    if (done) {
        return;
    }

    if (sourceMode != QueueDisposable.ASYNC) {
        queue.offer(t);
    }
    schedule();
}

继续看schedule

void schedule() {
    if (getAndIncrement() == 0) {
        worker.schedule(this);
    }
}

调用了worker的schedule方法,上面我们知道schedule里面完成线程切换,那我们就直接看看run方法

public void run() {
    if (outputFused) {
        drainFused();
    } else {
        drainNormal();
    }
}

上面判断了是否还有事件,否则就调用drainNormal,我们看一下drainNormal

void drainNormal() {
    int missed = 1;

    final SimpleQueue<T> q = queue;
    final Observer<? super T> a = actual;

    for (;;) {
        if (checkTerminated(done, q.isEmpty(), a)) {
            return;
        }

        for (;;) {
            boolean d = done;
            T v;

            try {
                v = q.poll();
            } catch (Throwable ex) {
                Exceptions.throwIfFatal(ex);
                s.dispose();
                q.clear();
                a.onError(ex);
                worker.dispose();
                return;
            }
            boolean empty = v == null;

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

            if (empty) {
                break;
            }

            a.onNext(v);
        }

        missed = addAndGet(-missed);
        if (missed == 0) {
            break;
        }
    }
 }

对队列进行了轮询发送事件,可以看出subscribeOn与observeOn的区别,subscribeOn是将整个事件的订阅执行线程进行切换,observeOn是对事件发送的线程进行切换