转载请保留原文链接:http://blog.csdn.net/u010593680/article/details/53911475
先看一个简单的使用,下例子在io线程中模拟获取了图片,并在主线程(Android)中输出了该图片:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {//getImage运行在subscribeOn设置的线程
String img = getImage();//获取图片,io线程
if (img != null) {
subscriber.onNext(img);
} else {
subscriber.onError(new IllegalStateException());
}
}
})
.subscribeOn(Schedulers.io())//设置上面操作运行在io线程
.observeOn(AndroidSchedulers.mainThread())//设置下方操作运行在主线程
.subscribe(new Action1<String>() {
@Override
public void call(String s) {//主线程中运行
Log.e(TAG, "图片:" + s);
}
});
接下来将对observeOn和subscribeOn两个方法的实现方式作解析。
observeOn(指定线程):改变下游操作运行的线程
public final Observable<T> observeOn(Scheduler scheduler) {
return observeOn(scheduler, RxRingBuffer.SIZE);
}
//最后会调用该方法
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
if (this instanceof ScalarSynchronousObservable) {
return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler);
}
return lift(new OperatorObserveOn<T>(scheduler, delayError, bufferSize));
}
使用了Lift生成一个新的Observable,并将OperatorObserveOn作为新Observable的OnSubscribe,不清楚Lift可查看我的上一篇blog,简要介绍Lift的操作就是能将下游的subscriber的传输给OperatorObserveOn,这也是observeOn方法能改变下游操作的线程的原因。
OperatorObserveOn的call方法将下游的subscriber包装成ObserveOnSubscriber:
@Override
public Subscriber<? super T> call(Subscriber<? super T> child) {
if (scheduler instanceof ImmediateScheduler) {
// avoid overhead, execute directly
return child;
} else if (scheduler instanceof TrampolineScheduler) {
// avoid overhead, execute directly
return child;
} else {
ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child, delayError, bufferSize);//包装并返回新的subscriber
parent.init();
return parent;
}
}
ObserveOnSubscriber简化代码:
/** Observe through individual queue per observer. */
private static final class ObserveOnSubscriber<T> extends Subscriber<T> implements Action0 {
public ObserveOnSubscriber(Scheduler scheduler, Subscriber<? super T> child, boolean delayError, int bufferSize) {
this.child = child;
this.recursiveScheduler = scheduler.createWorker();
//...
}
void init() {
// don't want this code in the constructor because `this` can escape through the
// setProducer call
Subscriber<? super T> localChild = child;
localChild.setProducer(new Producer() {//设置生产者
@Override
public void request(long n) {
if (n > 0L) {
BackpressureUtils.getAndAddRequest(requested, n);
schedule();
}
}
});
localChild.add(recursiveScheduler);
localChild.add(this);
}
@Override
public void onNext(final T t) {
if (isUnsubscribed() || finished) {
return;
}
//...
schedule();//切换线程
}
@Override
public void onCompleted() {
if (isUnsubscribed() || finished) {
return;
}
finished = true;
schedule();//切换线程
}
@Override
public void onError(final Throwable e) {
if (isUnsubscribed() || finished) {
RxJavaPlugins.getInstance().getErrorHandler().handleError(e);
return;
}
error = e;
finished = true;
schedule();//切换线程
}
protected void schedule() {
if (counter.getAndIncrement() == 0) {
recursiveScheduler.schedule(this);//在其他线程调用call方法
}
}
// only execute this from schedule()
@Override
public void call() {//schedule()调用后,在其他线程调用
//...
if (checkTerminated(done, empty, localChild, q)) {//检查是否已完成了,完成了调用onCompleted,onError方法
return;
}
localChild.onNext(localOn.getValue(v));
/...
}
}
boolean checkTerminated(boolean done, boolean isEmpty, Subscriber<? super T> a, Queue<Object> q) {
//该方法里会判断状态,可能调用onCompleted,onError等方法
if (a.isUnsubscribed()) {
q.clear();
return true;
}
if (done) {
if (delayError) {
if (isEmpty) {
Throwable e = error;
try {
if (e != null) {
a.onError(e);
} else {
a.onCompleted();
}
} finally {
recursiveScheduler.unsubscribe();
}
}
} else {
Throwable e = error;
if (e != null) {
q.clear();
try {
a.onError(e);
} finally {
recursiveScheduler.unsubscribe();
}
return true;
} else
if (isEmpty) {
try {
a.onCompleted();
} finally {
recursiveScheduler.unsubscribe();
}
return true;
}
}
}
return false;
}
}
由以上代码可以知道:
* observeOn以后会生成新的subscriber
* observeOn切换线程的时机是生产者生产出产品后,调用subscriber的onNext,onCompleted,onError方法时,此时会先切换线程,再调用onNext,onCompleted,onError
* observeOn不影响上游操作执行的线程
* observeOn可以切换多次下游操作的执行线程,因为lift可以多次包装生成新的Observable
subscribeOn(指定线程) :改变上游操作的运行线程
先看下代码:
public final Observable<T> subscribeOn(Scheduler scheduler) {
if (this instanceof ScalarSynchronousObservable) {
return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler);
}
return create(new OperatorSubscribeOn<T>(this, scheduler));//和observeOn不同的是并没使用lift,只对上游操作做了包装,因为subscribeOn改变的是上游操作
}
继续看下OperatorSubscribeOn:
public final class OperatorSubscribeOn implements OnSubscribe {
final Scheduler scheduler;
final Observable<T> source;
public OperatorSubscribeOn(Observable<T> source, Scheduler scheduler) {
this.scheduler = scheduler;//设置的线程调度器
this.source = source;//上游的observable
}
@Override
public void call(final Subscriber<? super T> subscriber) {
final Worker inner = scheduler.createWorker();
subscriber.add(inner);
inner.schedule(new Action0() {//在用户设置的线程里进行call操作
@Override
public void call() {//用户设置的线程里运行
final Thread t = Thread.currentThread();
Subscriber<T> s = new Subscriber<T>(subscriber) {//复制一个subscriber,只是简单包装,没做额外的操作
@Override
public void onNext(T t) {
subscriber.onNext(t);
}
@Override
public void onError(Throwable e) {
try {
subscriber.onError(e);
} finally {
inner.unsubscribe();
}
}
@Override
public void onCompleted() {
try {
subscriber.onCompleted();
} finally {
inner.unsubscribe();
}
}
@Override
public void setProducer(final Producer p) {
subscriber.setProducer(new Producer() {//线程切换的关键在这里
@Override
public void request(final long n) {
if (t == Thread.currentThread()) {//如果和用户设置的线程相同
p.request(n);
} else {
inner.schedule(new Action0() {//切换线程
@Override
public void call() {//在用户设置的线程里运行
p.request(n);//请求生产者生产出来的产品,即:生产者调用onNext等操作
}
});
}
}
});
}
};
source.unsafeSubscribe(s);
}
});
}
subscribeOn操作总结
- subscribeOn也是对subscriber作了包装
- subscribeOn会改变上游和下游的运行线程,(但如果调用了observeOn还是能切换下游线程,因为observeOn使用lift对下游操作进行了包装,所以即使subscribeOn改变了线程,observeOn的包装也会再次切换线程)
- 多个subscribeOn只有最上游的一个起作用
上面的第2点,举个例子,下面的程序只使用了一个subscribeOn也就是说上下游代码都执行在Schedulers.io()设置的线程里,所以下方设置图片就会崩溃:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {//getImage运行在subscribeOn设置的线程
String img = getImage();
if (img != null) {
subscriber.onNext(img);
} else {
subscriber.onError(new IllegalStateException());
}
}
})
.subscribeOn(Schedulers.io()) //subscribeOn 1
.subscribe(new Action1<String>() {
@Override
public void call(String s) {//Schedulers.io()
Log.e(TAG, "设置图片:" + s);
mIvDown.setImageResource(R.drawable.power_close);
}
});
上面的第3点不太好理解,举个例子:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {//getImage运行在subscribeOn设置的线程
String img = getImage();
if (img != null) {
subscriber.onNext(img);
} else {
subscriber.onError(new IllegalStateException());
}
}
})
.subscribeOn(Schedulers.io()) //subscribeOn 1
.subscribeOn(AndroidSchedulers.mainThread()) //subscribeOn 2
.subscribe(new Action1<String>() {
@Override
public void call(String s) {//subscribeOn 1线程,即Schedulers.io()
Log.e(TAG, "设置图片:" + s);
mIvDown.setImageResource(R.drawable.power_close);
//在非主线程操作,所以会崩溃
}
});
虽然subscribeOn2确实切换了线程2,但又给subscribeOn1切换到了线程1,之后再运行subscriber的onNext等方法
各个线程调度的内部实现:
- Schedulers.io()将操作放在线程池里运行,其schedule()方法立刻将操作调用Executor.submit方法,并且保存返回值future以便日后取消执行
- AndroidSchedulers.mainThread()使用Handler(MainLooper)方式在主线程调用操作
原文:http://blog.csdn.net/u010593680/article/details/53911475
部分内容可参考上一篇博客,如有问题欢迎指正~