即使在另一个线程上调用了subscribeOn(),Observable也会在主线程上运行

时间:2016-02-22 12:50:17

标签: java android rx-java rx-android

我在其中一项活动中遇到了一个奇怪的问题。 当从拍摄照片/视频回来时,在我的onActivityResult中,我正在显示一个对话框,让用户为相机命名。 一旦用户按下OK,我将onNext()发送给具有复制文件的请求文件名的主题​​(并显示进度对话框)。

由于某种原因,即使我调用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);
                }
            });
}

subscribeOn(Schedulers.io())来电更改为observeOn(Schedulers.io())解决了这个问题。 我仍然想知道为什么它没有工作......

1 个答案:

答案 0 :(得分:46)

subscribeOnobserveOn是最常混淆的运营商。前者确保订阅副作用发生在指定的调度程序(线程)上,但这并不意味着值也将在该线程上弹出。

例如,如果您的Observer在订阅它时打开网络连接,您不希望它在主线程上运行,因此,您需要subscribeOn来指定该订阅的位置,从而指定网络连接被创造。

当数据最终到达时,发送线程可以是任何内容,其中一个调度程序或后台普通旧线程。由于我们不知道或不喜欢该线程,因此我们希望将数据观察移至另一个线程。这就是observeOn的作用:确保后面的运算符将在指定的调度程序上执行onNext逻辑。 Android开发人员已经将它用于将值的观察结果移回主线程。

但很少解释的是,在最终结果再次出现在主线程上之前,当你想要在主线程上进行一些额外的计算时会发生什么:使用多个observeOn运算符:

source
.observeOn(Schedulers.computation())
.map(v -> heavyCalculation(v))
.observeOn(Schedulers.io())
.doOnNext(v -> { saveToDB(v); })
.observeOn(AndroidSchedulers.mainThread())
...