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

标签 java android rx-java rx-android

我在一项 Activity 中遇到了一个奇怪的问题。 从拍摄照片/视频回来时,在我的 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()) 解决了这个问题。 我还是想知道为什么它不起作用...

最佳答案

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

例如,如果您的观察者在订阅它时打开了一个网络连接,您不希望它在主线程上运行,因此,您需要 subscribeOn 来指定该订阅的位置,从而创建网络连接.

当数据最终到达时,发射线程可以是任何东西,调度程序之一或后台普通旧线程。由于我们不知道或不喜欢那个线程,我们希望将数据的观察转移到另一个线程。这就是 observeOn 所做的:确保运算符(operator)在它之后将在指定的调度程序上执行他们的 onNext 逻辑。 Android 开发人员已经使用它来将值的观察移回主线程。

但很少解释的是,当您希望在最终结果再次到达主线程之前从主线程进行一些额外的计算时会发生什么:使用多个 observeOn 运算符:

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

关于java - 即使 subscribeOn() 在另一个线程上调用,Observable 也会在主线程上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35554181/

相关文章:

java - 在 RxJava 中组合未知数量的 Observable

java - Thymeleaf 呈现空白页面

java - 在 GAE 上运行 Glassfish JAX-RS 服务器无法正常工作

java - 两堂课的最佳实践

android - 在 Android 中使用某些条件启用和禁用 Listview

android - 验证硬编码密码

android - 等待几个 observable 完成有/没有序列 Retrofit2 with rxjava - Android

java - 如何为Android Activity制作图标?

Android从图库中获取图像会旋转

android - MVP + RxJava - 将调度器放在 Presenter 或 Interactor 中?