Rx-JavaとRxandroid2を学んでいるだけで、SubscribeOnとObserveOnの主な違いは何なのか混乱しています。
SubscribeOnは、Observableが動作するスケジューラを指定します。 ObserveOnは、オブザーバがこのObservableを監視するスケジューラを指定します。
したがって、基本的にSubscribeOnはバックグラウンドスレッドでサブスクライブ(実行)され(オブザーバブルを待機している間にUIスレッドをブロックしたくない)、ObserveOnでメインスレッドで結果を監視したい...
AsyncTaskに精通している場合、SubscribeOnはdoInBackgroundメソッドに似ており、ObserveOnはonPostExecuteに似ています...
observeOn()
は、すべての演算子のスレッドをさらに変更するだけですDownstream。通常、これは誤解であり、observeOn
はupstreamとしても機能しますが、そうではありません。
以下の例で説明します。
_Observable.just("Some string") // UI
.map(str -> str.length()) // UI
.observeOn(Schedulers.computation()) // Changing the thread
.map(length -> 2 * length) // Computation
.subscribe(---)
_
subscribeOn()
のみinfluencesObservableがサブスクライブされ、ダウンストリームに留まるときに使用されるスレッド。
_Observable.just("Some String") // Computation
.map(str -> str.length()) // Computation
.map(length -> 2 * length) // Computation
.subscribeOn(Schedulers.computation()) // -- changing the thread
.subscribe(number -> Log.d("", "Number " + number));// Computation
_
位置は関係ありません(
subscribeOn()
)
どうして?なぜなら、はサブスクリプションの時間にのみ影響するからです。
subscribeOn
との接触に従う方法
->基本的な例:_Observable.create
_
create
本体内で指定されたすべての作業は、subscribeOn
で指定されたスレッドで実行されます。
別の例:_Observable.just
_、_Observable.from
_または_Observable.range
_
注:これらのすべてのメソッドは値を受け入れるため、subscribeOnは影響しないため、ブロッキングメソッドを使用してそれらの値を作成しないでください。
ブロッキング関数を使用する場合は、使用します
Observable.defer(() -> Obervable.just(blockingMenthod())));
重要な事実:
subscribeOnはSubjects
では機能しません
複数の
subscribeOn
:
ストリームにsubscribeOn
のインスタンスが複数ある場合、firstのみが実際的な効果を持ちます。
購読&
subscribeOn
subscribeOn
は_Observable.subscribe
_と関係があると考えられますが、特別なことはありません。 サブスクリプション段階にのみ影響します。
tl; dr上記のいずれにも意味がない場合は、このコードスニペットを見てください
_ Observable.just("Some string")
.map(str -> str.length())
.observeOn(Schedulers.computation())
.map(length -> 2 * length)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(---)
_
オブザーバブルを観察し、[〜#〜] ui [〜#〜]スレッドでマップ機能を実行し、計算スレッドと
map(length -> 2 * length)
機能の実行により、Mainスレッド。ただし、[〜#〜] io [〜#〜]スレッドのsubscribe()
で定義されているすべてのタスクを実行します。
出典:トメク・ポラスキー( Medium )
observeOn
またはdoOnNext
内のコードブロックなど、コールバック "ストリームのさらに下(下)"のスレッドを設定するには、map
を使用します。subscribeOn
を使用して、初期化 "upstream(above it)"のスレッドを設定します。たとえば、doOnSubscribe
、_Observable.just
_、_Observable.create
_などです。例でこのトピックを見ていきましょう。文字列「user1032613」の長さを見つけたいです。これはコンピューターにとって簡単な作業ではないため、アプリのフリーズを避けるために、バックグラウンドスレッドで集中的な計算を実行するのは当然です。
observeOn
を何度でも呼び出すことができ、すべてのスレッドを制御しますその下のコールバックを実行します。使い方は簡単で、期待どおりに機能します。
たとえば、メインUIスレッドに進行状況バーを表示してから、別のスレッドで集中/ブロッキング操作を実行し、メインUIスレッドに戻って結果を更新します。
_ Observable.just("user1032613")
.observeOn(mainThread) // set thread for operation 1
.doOnNext {
/* operation 1 */
print("display progress bar")
progressBar.visibility = View.VISIBLE
}
.observeOn(backThread) // set thread for operation 2 and 3
.map {
/* operation 2 */
print("calculating")
Thread.sleep(5000)
it.length
}
.doOnNext {
/* operation 3 */
print("finished calculating")
}
.observeOn(mainThread) // set thread for operation 4
.doOnNext {
/* operation 4 */
print("hide progress bar and display result")
progressBar.visibility = View.GONE
resultTextView.text = "There're $it characters!"
}
.subscribe()
_
上の例では、mainThread
で_/* operation 1 */
_が実行されます。これは、そのすぐ上の行でobserveOn(mainThread)
を使用して設定するためです。次に、backThread
を再度呼び出してobserveOn
に切り替えるので、_/* operation 2 */
_がそこで実行されます。 _/* operation 3 */
_をチェーンする前に変更しなかったため、_/* operation 2 */
_と同様に、バックスレッドでも実行されます。最後に、observeOn(mainThread)
を再度呼び出して、_/* operation 4 */
_がメインスレッドからUIを更新することを確認します。
したがって、observeOn
は後続のコールバックのスレッドを設定することを学びました。他に何が欠けていますか?まあ、Observable
自体、およびjust()
、create()
、subscribe()
などのメソッドも実行する必要があるコードです。 。これは、オブジェクトがストリームに沿って渡される方法です。 subscribeOn
に関連するコードのスレッドを設定するには、Observable
を使用します。
すべてのコールバック(前述のobserveOn
で制御)を削除すると、デフォルトでは、コードが記述されているスレッド(おそらくメインスレッド)で実行される「スケルトンコード」が残ります。
_ Observable.just("user1032613")
.observeOn(mainThread)
.doOnNext {
}
.observeOn(backThread)
.map {
}
.doOnNext {
}
.observeOn(mainThread)
.doOnNext {
}
.subscribe()
_
メインスレッドで実行されるこの空のスケルトンコードに満足できない場合は、subscribeOn
を使用して変更できます。たとえば、最初の行Observable.just("user1032613")
は、ユーザー名からストリームを作成するほど簡単ではないかもしれません-インターネットからの文字列であるか、または他の集中的にdoOnSubscribe
を使用している可能性があります操作。その場合、subscribeOn(backThread)
を呼び出して、コードの一部を別のスレッドに入れることができます。
subscribeOn
この答えを書いている時点では、「一度だけ呼び出す」、「位置は関係ない」、「複数回呼び出す場合、最初の時間だけがカウントされる」という誤解があります。多くの調査と実験の結果、subscribeOn
を複数回呼び出すと便利なことがわかりました。
Observable
は Builderパターン (「次々にメソッドをチェーンする」ための仮名)を使用するため、subscribeOn
は逆の順序で適用されます。したがって、このメソッドは上記のコードのスレッドを設定します。これはobserveOn
の正反対です。
doOnSubscribe
メソッドを使用してこれを実験できます。このメソッドは、サブスクリプションイベントでトリガーされ、subscribeOn
で設定されたスレッドで実行されます。
_ Observable.just("user1032613")
.doOnSubscribe {
print("#3 running on main thread")
}
.subscribeOn(mainThread) // set thread for #3 and just()
.doOnNext {
}
.map {
}
.doOnSubscribe {
print("#2 running on back thread")
}
.doOnNext {
}
.subscribeOn(backThread) // set thread for #2 above
.doOnNext {
}
.doOnSubscribe {
print("#1 running on default thread")
}
.subscribe()
_
Builderパターンがコードを実行する方法と同じように、上記の例を下から上に読むと、ロジックに従う方が簡単かもしれません。
この例では、最初の行Observable.just("user1032613")
はprint("#3")
と同じスレッドで実行されます。これは、それらの間にsubscribeOn
がなくなるためです。これにより、just()
またはcreate()
内のコードのみに関心がある人にとっては、「最初の呼び出しだけが重要」という錯覚が生じます。これは、 さらに作業を始めるとすぐにバラバラになります 。
例のスレッドとprint()
関数は、簡潔にするために次のように定義されています。
_val mainThread = AndroidSchedulers.mainThread()
val backThread = Schedulers.computation()
private fun print(msg: String) = Log.i("", "${Thread.currentThread().name}: $msg")
_
誰かがrx Java説明を理解するのが難しい(たとえば私として))を見つけた場合、純粋なJava説明:
_Observable.just("something")
.subscribeOn(Schedulers.newThread())
.subscribe(...);
_
以下と同等です:
_Observable observable = Observable.just("something");
new Thread(() -> observable.subscribe(...)).start();
_
Observable
はsubscribe()
で値を発行し、ここでsubscribe()
は別のスレッドで送信されるため、値はsubscribe()
と同じスレッドで発行されます。これが「上流」(以前の操作のスレッドに影響を与える)および「下流」で機能する理由です。
_Observable.just("something")
.observeOn(Schedulers.newThread())
.subscribe(...);
_
以下と同等です:
_Observable observable = Observable.just("something")
.subscribe(it -> new Thread(() -> ...).start());
_
ここでObservable
はメインスレッドで値を出力し、リスナーメソッドのみが別のスレッドで実行されます。