RxJava之Connectable Observable

811 阅读4分钟

文中的源代码版本为v2.2.0

RxJava之Connectable Observable

先总结

  1. 重复订阅的实现?
    使用一个PublishObserver保存所有通过subscribe方法进行订阅的订阅者。再由PublishObserver订阅原始的ObservablePublishObserver接收到消息之后再依次派发给其保存的订阅者。
  2. 如何控制消息在connect方法调用之后才开始发送?
    只有在调用源Observablesubscribe方法之后,消息才会真正开始发送。Connectable Observable正是利用了这一点,将subscribe方法的调用放在了connect方法中,实现了控制消息发送时机的功能。

Connectable Observable区别于普通Observable的地方在于

  1. 可以被重复订阅
  2. 被订阅之后并不会马上开始发送消息,只有在调用了Connect操作符之后才会开始发送消息

本文的目的就是想通过阅读源码的形式去了解Connectable Observable的上述功能是如何实现的。

通过调用Publish操作符可以将普通的Observable转化为Connectable ObservableObservable.publish函数非常简单,内部调用了ObservablePublish.create(this),我们直接贴该函数的代码

ObservablePublish.create

create的主要工作:

  1. 创建一个PublishObserverAtomicReference对象。PublishObserver实现了Observer接口,我们可以将它看做是一个观察者
  2. 创建一个PublishSource对象
  3. 创建并返回一个ObservablePublish对象。ObservablePublish继承自ConnectableObservable
//ObservablePublish.java

public static <T> ConnectableObservable<T> create(ObservableSource<T> source) {
    final AtomicReference<PublishObserver<T>> curr = new AtomicReference<PublishObserver<T>>();
    ObservableSource<T> onSubscribe = new PublishSource<T>(curr);
    return new ObservablePublish<T>(onSubscribe, source, curr);
}

PublishSource(AtomicReference<PublishObserver<T>> curr) {
    this.curr = curr;
}

private ObservablePublish(ObservableSource<T> onSubscribe, ObservableSource<T> source,
                              final AtomicReference<PublishObserver<T>> current) {
    this.onSubscribe = onSubscribe;
    this.source = source;
    this.current = current;
}

Connectable Observable创建完毕,我们接着看看subscribe函数里面做了什么。我们知道subscribe最终会调用subscribeActual

ObservablePublish.subscribeActual

 protected void subscribeActual(Observer<? super T> observer) {
    onSubscribe.subscribe(observer);
}

该方法只有一句代码,onSubscribe的类型是PublishSource,我们继续跟下去

PublishSource.onSubscribe

 public void subscribe(Observer<? super T> child) {
    // create the backpressure-managing producer for this child
    InnerDisposable<T> inner = new InnerDisposable<T>(child);
    child.onSubscribe(inner);
    // concurrent connection/disconnection may change the state,
    // we loop to be atomic while the child subscribes
    for (;;) {
        // get the current subscriber-to-source
        PublishObserver<T> r = curr.get();
        // if there isn't one or it is disposed
        if (r == null || r.isDisposed()) {
            // create a new subscriber to source
            PublishObserver<T> u = new PublishObserver<T>(curr);
            // let's try setting it as the current subscriber-to-source
            if (!curr.compareAndSet(r, u)) {
                // didn't work, maybe someone else did it or the current subscriber
                // to source has just finished
                continue;
            }
            // we won, let's use it going onwards
            r = u;
        }

        /*
         * Try adding it to the current subscriber-to-source, add is atomic in respect
         * to other adds and the termination of the subscriber-to-source.
         */
        if (r.add(inner)) {
            inner.setParent(r);
            break; // NOPMD
        }
    }
}
  
//PublishObserver.java
final AtomicReference<InnerDisposable<T>[]> observers;
boolean add(InnerDisposable<T> producer) {
    // the state can change so we do a CAS loop to achieve atomicity
    for (;;) {
        // get the current producer array
        InnerDisposable<T>[] c = observers.get();
        // if this subscriber-to-source reached a terminal state by receiving
        // an onError or onComplete, just refuse to add the new producer
        if (c == TERMINATED) {
            return false;
        }
        // we perform a copy-on-write logic
        int len = c.length;
        @SuppressWarnings("unchecked")
        InnerDisposable<T>[] u = new InnerDisposable[len + 1];
        System.arraycopy(c, 0, u, 0, len);
        u[len] = producer;
        // try setting the observers array
        if (observers.compareAndSet(c, u)) {
            return true;
        }
        // if failed, some other operation succeeded (another add, remove or termination)
        // so retry
    }
}
    

主要干了两件事情:

  1. 创建一个PublishObserver对象,并保存起来
  2. subscribe函数传递进来的Observer包装成InnerDisposable对象添加到PublishObserver中。PublishObserver使用一个数组来保存InnerDisposable

代码中的for循环以及一些AtomicReference的操作,我们可以不用太理会,主要是用来解决并发问题,于流程并没有太大影响。

好了,现在我们可以总结出两个事情

  1. 调用Connectable Observablesubscribe函数并不会触发消息的发送,原因是它并没有调用源Observablesubscribe函数
  2. 通过Connectable Observablesubscribe函数传递进来的Observer都会被保存在一个PublishObserver中。

消息的订阅已经完成,那么下面就是发送消息了,Connectable Observable只有在调用了connect方法之后才会开始发送消息,我们接着看

ConnectableObservable.connect

connect方法最终会进入到下面这个重载的connect方法中

public void connect(Consumer<? super Disposable> connection) {
    boolean doConnect;
    PublishObserver<T> ps;
    // we loop because concurrent connect/disconnect and termination may change the state
    for (;;) {
        // retrieve the current subscriber-to-source instance
        ps = current.get();
        //这个if语句的核心逻辑就是创建一个PublishObserver对象
        //如果之前掉用过subscribe方法,那么此处PublishObserver
        //是不为null的
        if (ps == null || ps.isDisposed()) {
            // create a new subscriber-to-source
            PublishObserver<T> u = new PublishObserver<T>(current);
            // try setting it as the current subscriber-to-source
            if (!current.compareAndSet(ps, u)) {
                // did not work, perhaps a new subscriber arrived
                // and created a new subscriber-to-source as well, retry
                continue;
            }
            ps = u;
        }
        //shouldConnect为AtomicBoolean类型,确保并发场景下只触发一次
        doConnect = !ps.shouldConnect.get() && ps.shouldConnect.compareAndSet(false, true);
        break; // NOPMD
    }
    //...
    if (doConnect) {
        source.subscribe(ps);
    }
}

//PublishObserver.java
public void onNext(T t) {
    for (InnerDisposable<T> inner : observers.get()) {
        inner.child.onNext(t);
    }
}

可以看到,connect方法最最核心的功能就是调用原始Observablesubscribe方法,订阅者是PublishObserver。 再看PublishObserver.onNext方法,PublishObserver在接收到消息之后会遍历内部的数组,将消息挨个发送给之前保存起来的Observer