我一直试图确定为什么.flatMap()
运算符中的以下代码显示在主线程上运行:
public Observable<Void> getObservable() {
return jobServiceObservable
.flatMap(jobService -> {
if (Looper.myLooper() == Looper.getMainLooper()) {
Log.d("LooperTest", "On main thread.");
} else {
Log.d("LooperTest", "Not on main thread.");
}
return jobService.syncReservations(accountUtil.getCurrentAccount());
})
.subscribeOn(Schedulers.io()).observeOn(foregroundScheduler);
}
如您所见,使用.subscribeOn()
调用Schedulers.io()
,但是日志语句显示.flatMap()
内的代码是在主线程上运行的:
LooperTest:在主线程上。
作为一项完整性检查,我在此代码的各个部分添加了对.subscribeOn(Schedulers.io())
的额外调用:
public Observable<Void> getObservable() {
return jobServiceObservable.subscribeOn(Schedulers.io())
.flatMap(jobService -> {
if (Looper.myLooper() == Looper.getMainLooper()) {
Log.d("LooperTest", "On main thread.");
} else {
Log.d("LooperTest", "Not on main thread.");
}
return jobService.syncReservations(accountUtil.getCurrentAccount()).subscribeOn(Schedulers.io());
})
.subscribeOn(Schedulers.io()).observeOn(foregroundScheduler);
}
但是,日志语句似乎显示相同的结果。接下来,在没有任何代码更改的情况下,我清理了构建并重新启动了我的模拟器。下次运行时,打印出以下内容:
LooperTest:不在主线程上。
这很奇怪,因为没有进行任何代码更改。同样,在没有代码更改的情况下,我清理了构建并重新启动了模拟器。在下一次运行中,打印了以下内容:
LooperTest:在主线程上。
再一次,我清理了构建,然后关闭并打开了一个不同类型的新模拟器。运行后,打印出以下内容:
LooperTest:不在主线程上。
为什么会这样?我怀疑有一些奇怪的缓存机制在起作用。
此外,请注意jobService.syncReservations()
会返回BehaviorSubject
。通过各种搜索,Subjects
可能会或可能不会尊重对.subscribeOn()
的调用。
最后,请注意jobServiceObservable
被注入到定义上述代码的文件中。 jobServiceObservable
是通过以下代码创建的:
public Observable<JobService> getObservable() {
return Observable.create(e -> {
if (jobServiceBound && jobService != null) {
e.onNext(jobService);
e.onComplete();
} else {
jobServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
JobService.JobServiceBinder binder = (JobService.JobServiceBinder) service;
jobService = binder.getService();
jobServiceBound = true;
e.onNext(jobService);
e.onComplete();
}
@Override
public void onServiceDisconnected(ComponentName name) {
reset();
}
};
try {
boolean success = context.bindService(new Intent(context, JobService.class), jobServiceConnection, Context.BIND_AUTO_CREATE);
if (!success) {
e.onError(new Throwable("The service failed to be bound."));
}
} catch (SecurityException exception) {
e.onError(exception);
}
}
});
}
需要有关为何发生上述行为的权威答案。
答案 0 :(得分:2)
因为在订阅onServiceConnected
调度程序上的包Observable
之后,系统方式在主线程上调用了io()
。 subscribeOn
告诉我们进一步订阅的位置,或者在这种情况下,应该执行Observable.create()
的正文。您应该在observeOn
之前使用flatMap
,以便在所需的线程上执行mapper函数:
public Observable<Void> getObservable() {
return jobServiceObservable
.observeOn(Schedulers.io())
.flatMap(jobService -> {
if (Looper.myLooper() == Looper.getMainLooper()) {
Log.d("LooperTest", "On main thread.");
} else {
Log.d("LooperTest", "Not on main thread.");
}
return jobService.syncReservations(
accountUtil.getCurrentAccount()).subscribeOn(Schedulers.io());
})
.observeOn(foregroundScheduler);
}
(相反,对于典型的Retrofit网络调用,subscribeOn
有效,因为网络库在给定的调度程序上执行其阻塞调用,并保留在那里以发出网络响应。)