即使在另一个线程上调用subscribeOn(),也可以在主线程上运行 [英] Observable runs on main thread even though subscribeOn() is called on another thread

查看:312
本文介绍了即使在另一个线程上调用subscribeOn(),也可以在主线程上运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的一项活动遇到了一个奇怪的问题. 从拍照/录像回来时,在我的onActivityResult中,我将显示一个对话框,允许用户为相机命名. 用户按下OK后,我将onNext()发送给具有所请求文件名的主题​​,该主题将复制文件(并显示进度对话框).

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).

由于某种原因,即使我调用subscribeOn(Schedulers.io()),也总是在主线程上调用执行复制的map()函数.

For some reason the map() function that does the copy is always called on the main thread, even though I call 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())解决了该问题. 我还是想知道为什么它不起作用...

Changing the subscribeOn(Schedulers.io()) call to observeOn(Schedulers.io()) solved the issue. Still I would like to know why it didn't work...

推荐答案

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

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来指定该订阅的位置,从而创建网络连接

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.

当数据最终到达时,发出线程可以是任何东西,既可以是调度程序之一,也可以是后台普通旧线程.由于我们不知道或不喜欢该线程,因此我们希望将对数据的观察移到另一个线程.这是observeOn的作用:确保操作符之后的操作符将在指定的调度程序上执行其onNext逻辑. Android开发人员已经使用它来将对值的观察移回主线程.

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运算符:

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:

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

这篇关于即使在另一个线程上调用subscribeOn(),也可以在主线程上运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆