在关于Observable变种之五大金刚一文分析中,我们知道Observable在收到Observer订阅的时候,就会立即发送数据,既为冷发射。而热发射既只是为Observable和Observer之间建立了订阅管道,并不会直接发射数据,而是在有需要的时候才发射数据。而热发射的场景就有很多了,因为热发射我们可以决定发射时机、地点、数据。
四大热发射集成自抽象Subject,而Subject集继承自Observable,同时还实现了Observer,因此实际既可以作为Observable,还可以作为Observer。既然四大热发射都继承自Observable,所以订阅仍然形如Observable.subscribe(observer), 订阅之后仍然具体走到subscribeActual具体方法中,因此本文将四大热发射称为Observable的变种。
PublishSubject——接收订阅之后的所有数据
PublishSubject<String> publish = PublishSubject.create();
publish.subscribe(new PublishObserver<String>("first"));
publish.onNext("1");
publish.onNext("2");
publish.subscribe(new PublishObserver<String>("seconde"));
publish.onNext("3");
publish.onCompleted();
如上例子,则第一个订阅的观察者将收到1、2、3数据,而第二个订阅的观察者只收到3的数据。此处,在PublishSubject中有一个保存订阅者的属性,是个数组,可以通过分析代码知道,当发送数据后,就会遍历这个数组的订阅者,发射数据到各个订阅者中。
final AtomicReference<PublishSubject.PublishDisposable<T>[]> subscribers;
BehaviorSubject——释放订阅前最后一个数据和订阅后的所有数据
BehaviorSubject<String> behavior = BehaviorSubject.create("deafault");
behavior.subscribe(new SubjectObserver<String>("first"));
behavior.onNext("1");
behavior.onNext("2");
behavior.subscribe(new SubjectObserver<String>("seconde"));
behavior.onNext("3");
behavior.onCompleted();
上面例子中,第一个订阅者讲收到包括default在内的1、2、3数据,而第二个订阅将收到订阅前的最后一条数据2,后面的所有数据3。那么BehaviorSubject是怎么收到在订阅前的最后一条数据的呢?如下
protected void subscribeActual(Observer<? super T> observer) {
BehaviorSubject.BehaviorDisposable<T> bs = new BehaviorSubject.BehaviorDisposable(observer, this);
observer.onSubscribe(bs);
if (this.add(bs)) {
if (bs.cancelled) {
this.remove(bs);
} else {
bs.emitFirst();
}
} else {
Throwable ex = (Throwable)this.terminalEvent.get();
if (ex == ExceptionHelper.TERMINATED) {
observer.onComplete();
} else {
observer.onError(ex);
}
}
}
订阅时进入到我们熟悉的subscribeActual方法,然后进入bs.emitFirst()中,如下:
void emitFirst() {
if (!this.cancelled) {
Object o;
synchronized(this) {
if (this.cancelled) {
return;
}
if (this.next) {
return;
}
BehaviorSubject<T> s = this.state;
Lock lock = s.readLock;
lock.lock();
this.index = s.index;
o = s.value.get();
lock.unlock();
this.emitting = o != null;
this.next = true;
}
if (o != null) {
if (this.test(o)) {
return;
}
this.emitLoop();
}
}
}
主要看this.test(o),此时如果上次有发射,则o为相关发射。
ReplaySubject——将所有接收到的数据或通知全部发送给订阅者
ReplaySubject<String> replay = ReplaySubject.create();
replay.subscribe(new SubjectObserver<String>("first"));
replay.onNext("1");
replay.onNext("2");
replay.subscribe(new SubjectObserver<String>("seconde"));
replay.onNext("3");
replay.onCompleted();
上面例子中,第一个订阅者将收到1、2、3和complete通知,第二个订阅者也是收到1、2、3和complete通知。
protected void subscribeActual(Observer<? super T> observer) {
ReplaySubject.ReplayDisposable<T> rs = new ReplaySubject.ReplayDisposable(observer, this);
observer.onSubscribe(rs);
if (!rs.cancelled) {
if (this.add(rs) && rs.cancelled) {
this.remove(rs);
return;
}
this.buffer.replay(rs);
}
}
订阅之后,进入subscribeActual方法,this.buffer为SizeAndTimeBoundReplayBuffer的实例。走到this.buffer.replay(rs)中,进入到下面代码:
public void replay(ReplaySubject.ReplayDisposable<T> rs) {
if (rs.getAndIncrement() == 0) {
int missed = 1;
Observer<? super T> a = rs.actual;
ReplaySubject.TimedNode<Object> index = (ReplaySubject.TimedNode)rs.index;
if (index == null) {
index = this.getHead();
}
while(!rs.cancelled) {
while(!rs.cancelled) {
ReplaySubject.TimedNode<Object> n = (ReplaySubject.TimedNode)index.get();
if (n == null) {
if (index.get() == null) {
rs.index = index;
missed = rs.addAndGet(-missed);
if (missed == 0) {
return;
}
}
} else {
Object o = n.value;
if (this.done && n.get() == null) {
if (NotificationLite.isComplete(o)) {
a.onComplete();
} else {
a.onError(NotificationLite.getError(o));
}
rs.index = null;
rs.cancelled = true;
return;
}
a.onNext(o);
index = n;
}
}
rs.index = null;
return;
}
rs.index = null;
}
}
上面代码既是为啥在订阅个第二个订阅者的时候,会响应收到数据1、2。这里大概分析一下,我们看到,ReplaySubject主要维护了一个ReplaySubject.TimedNode链表,凡是发射过的都会进入到这个链表中保存,因此通过遍历这个链表,然后发个后来的订阅者。
AsyncSubject——当发送onComplete才会发送最后一条数据
AsyncSubject async = AsyncSubject.create();
async.subscribe(new SubjectObserver<String>("first"));
async.onNext("1");
async.onNext("2");
async.onNext("3");
async.onCompleted();
async.subscribe(new SubjectObserver<String>("seconde"));
async.onCompleted();
上面例子中,第一个订阅者发送了3个数据,只有送到onCompleted的时候,订阅者才接受最后一条数据3,同样的,第二个订阅者订阅之后,就直接发送onCompleted,那么第二订阅者也同样收到数据3.
具体分析如下:发送onNext的时候,会保存当前数据到属性value中,这个value后面用到。
public void onNext(T t) {
ObjectHelper.requireNonNull(t, "onNext called with null. Null values are generally not allowed in 2.x operators and sources.");
if (this.subscribers.get() != TERMINATED) {
this.value = t;
}
}
当发送onComplete的时候,代码如下:
public void onComplete() {
if (this.subscribers.get() != TERMINATED) {
T v = this.value;
AsyncSubject.AsyncDisposable<T>[] array = (AsyncSubject.AsyncDisposable[])this.subscribers.getAndSet(TERMINATED);
AsyncSubject.AsyncDisposable[] var3;
int var4;
int var5;
AsyncSubject.AsyncDisposable as;
if (v == null) {
var3 = array;
var4 = array.length;
for(var5 = 0; var5 < var4; ++var5) {
as = var3[var5];
as.onComplete();
}
} else {
var3 = array;
var4 = array.length;
for(var5 = 0; var5 < var4; ++var5) {
as = var3[var5];
as.complete(v);
}
}
}
}
则当value不为空的时候,遍历订阅者数组,从而调用as.complete(v),as为DeferredScalarDisposable实例,complete的具体实现如下:
public final void complete(T value) {
int state = this.get();
if ((state & 54) == 0) {
if (state == 8) {
this.value = value;
this.lazySet(16);
} else {
this.lazySet(2);
}
Observer<? super T> a = this.actual;
a.onNext(value);
if (this.get() != 4) {
a.onComplete();
}
}
}
从而调用订阅者的onNext方法,输出相关的数据。
通过上面的分析,我们知道,热发射相对冷发射提供了很多方便,它并不会要求订阅者订阅之后就要马上接收数据,相反的,根据需要,在特定的场景下进行相关的数据的发射,使得我们更加灵活运用。