java 即使在另一个线程上调用 subscribeOn() ,Observable 也会在主线程上运行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35554181/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Observable runs on main thread even though subscribeOn() is called on another thread
提问by Yoshkebab
I got a weird issue in one of my activities.
When coming back from taking a picture / video, in my onActivityResult
I am showing a dialog that lets the user name the camera.
Once the user presses OK, I send onNext()
to a subject with the requested file name that copies the file (and shows progress dialog).
我在我的一项活动中遇到了一个奇怪的问题。从拍摄照片/视频回来时,我将onActivityResult
显示一个对话框,让用户为相机命名。一旦用户按下“确定”,我就会将onNext()
复制文件的请求文件名发送给主题(并显示进度对话框)。
For some reason the map()
function that does the copy is always called on the main thread, even though I call subscribeOn(Schedulers.io())
.
出于某种原因map()
,执行复制的函数总是在主线程上调用,即使我调用subscribeOn(Schedulers.io())
.
@Override
protected void onActivityResult(final int requestCode, int resultCode, Intent intent) {
...
final PublishSubject<String> subject = PublishSubject.create();`
mSubscription = subject
.subscribeOn(Schedulers.io())
.map(new Func1<String, String>() {
@Override
public String call(String fileName) {
Log.I.d(TAG,"map");
return doSomeIOHeavyFuncition();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
@Override
public void call(final String fullPath) {
Log.d(TAG,"onNext");
doSomethingOnUI(fullPath);
subject.onCompleted();
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
...
}
}, new Action0() {
@Override
public void call() {
...
}
});
final AlertDialog dialog = new AlertDialog.Builder
....
.create()
.show();
dialog.getButton(DialogInterface.BUTTON_POSITIVE)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String someString = getStringFromDialog(dialog);
dialog.dismiss();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(input.getWindowToken(), 0);
showProgressDialog();
subject.onNext(someString);
}
});
}
Changing the subscribeOn(Schedulers.io())
call to observeOn(Schedulers.io())
solved the issue.
Still I would like to know why it didn't work...
更改subscribeOn(Schedulers.io())
呼叫以observeOn(Schedulers.io())
解决问题。我仍然想知道为什么它不起作用......
回答by akarnokd
subscribeOn
and observeOn
is the mostly confused operators there are. The former makes sure that subscription side effects happen on the specified scheduler (thread), but that doesn't mean that values will pop up on that thread as well.
subscribeOn
并且observeOn
是最容易混淆的运算符。前者确保订阅副作用发生在指定的调度程序(线程)上,但这并不意味着值也会在该线程上弹出。
For example, if your Observer opens a network connection when one subscribes to it, you don't want that to run on the main thread, therefore, you need subscribeOn to specify where that subscription and thus the network connection will be created.
例如,如果您的观察者在订阅时打开一个网络连接,您不希望它在主线程上运行,因此,您需要 subscribeOn 指定该订阅的位置,从而创建网络连接。
When data finally arrives, the emitting thread can be anything, one of the schedulers or a background plain old thread. Since we don't know or don't like that thread, we want to move the observation of the data to another thread. This is what observeOn does: makes sure operators after it will execute their onNext logic on the specified scheduler. Android devs use it already to move the observation of values back to the main thread.
当数据最终到达时,发射线程可以是任何东西,调度程序之一或后台普通旧线程。由于我们不知道或不喜欢那个线程,我们想将数据的观察转移到另一个线程。这就是observeOn所做的:确保操作员在指定的调度程序上执行他们的onNext逻辑之后。Android 开发人员已经使用它来将值的观察移回主线程。
What's rarely explained though is what happens when you want some extra computation off the main thread before the final result lands on the main thread again: use multiple observeOn
operators:
但是很少有人解释的是,当您希望在最终结果再次落在主线程上之前从主线程中进行一些额外的计算时会发生什么:使用多个observeOn
运算符:
source
.observeOn(Schedulers.computation())
.map(v -> heavyCalculation(v))
.observeOn(Schedulers.io())
.doOnNext(v -> { saveToDB(v); })
.observeOn(AndroidSchedulers.mainThread())
...