web-dev-qa-db-ja.com

BlockingGetブロックUIスレッドRxJava2

私はその問題に取り組んでいます。

同期してRxJavaを呼び出そうとしていますが、そうするとメインスレッドがブロックされます。

これが私のコードです

   @Override
    public Single<SettingsBundle> getSettings() {
        SettingsBundle settingsModel = mSettingsManager.getSettings();
        return Single.just(settingsModel).map(mSettingsMapper);
    }

そして、これが私の同期呼び出しです

   @Override
    public SettingsBundle getSettingsSync() {
        return getSettings().blockingGet();
    }

getSettingsSyncを呼び出すと、メインスレッドがブロックされますが、正常に動作する場合があります。さらに問題があります。

私はそのようなことを試みました

@Override
public SettingsBundle getSettingsSync() {
    return getSettings()
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .blockingGet();
}

しかし、それはまだブロックされたままです。

私が間違っていること、私はどんな助けにも感謝するでしょう。

ありがとう。

6
user4671628

TL; TR

observeOn(AndroidSchedulers.mainThread())blockingGet()と一緒に使用しないでください


ロングバージョン

次の出力:

_class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val result =
                Single.just("Hello")
                .subscribeOn(Schedulers.io())
               // .observeOn(AndroidSchedulers.mainThread())
                .map {
                    println("1. blockingGet `$it` thread: ${Thread.currentThread()}")
                    return@map it
                }
                .blockingGet()
        println("2. blockingGet `$result` thread: ${Thread.currentThread()}")
    }
}
_

です

_ 1. blockingGet `Hello` thread: Thread[RxCachedThreadScheduler-1,5,main]
 2. blockingGet `Hello` thread: Thread[main,5,main]
_

結果がメインスレッドで生成されたことがわかるように(2行目)、map関数はRxCachedThreadSchedulerスレッドで実行されました。

.observeOn(AndroidSchedulers.mainThread())の行が削除されると、blockingGet()は二度と戻らず、すべてがスタックします。

10
_.observeOn(AndroidSchedulers.mainThread())
.blockingGet();
_

問題は、この特定の演算子の組み合わせに存在します。 AndroidSchedulersは、コードがメインスレッドで実行されるようにスケジュールしますが、blockingGet()は、そのスレッドでのコードの実行を停止します。簡単に言えば、AndroidSchedulersRxJavaのブロッキング演算子は一緒にうまく機能しません。

Androidスケジューラーはオブザーバブルの構築に使用される可能性があるため、これは、メインスレッドで_blocking*_演算子を使用すると、何をしようとしてもデッドロックが発生しやすくなることを意味します。 。

3
Kiskae

メインスレッドで実行する関数が本当に必要であり、同期する必要がある場合は、次のようにすることができます。

  1. これがメインスレッド(Looper.myLooper() == Looper.getMainLooper())の場合は、func()を実行します。

  2. メインスレッドにない場合は、observeOn(AndroidSchedulers.mainThread())blockingGet()の組み合わせを使用できます。

0
rajath