Skip to content

SubscribeOnMainThread

1. 概要

SubscribeOnMainThread は、ソース Observable への実際の購読処理を Unity のメインスレッドで実行する R3.Unity のオペレーターです。内部的には SubscribeOn(UnityFrameProvider.Update) と同義です。

購読時に Unity API を触る Observable、または GameObject / Component の状態を購読開始時に読む Observable では、購読処理を Unity メインスレッドへ寄せたい場合があります。

2. シグネチャ

csharp
public static Observable<T> SubscribeOnMainThread<T>(
    this Observable<T> source)

3. マーブルダイアグラム

SubscribeOnMainThread のマーブルダイアグラム

値自体は変更されません。ソースへの購読開始が Unity のメインスレッド(Update)で行われます。

4. サンプルコード

csharp
Observable
    .Create<Unit>(observer =>
    {
        // Unity API に触れる購読初期化をメインスレッドで実行したい
        transform.position = Vector3.zero;
        observer.OnNext(Unit.Default);
        observer.OnCompleted();
        return Disposable.Empty;
    })
    .SubscribeOnMainThread()
    .Subscribe()
    .AddTo(this);

5. 補足

ObserveOnMainThread との違い

SubscribeOnMainThread が制御するのは購読処理の実行場所です。OnNext などの通知を Unity メインスレッドで受け取りたい場合は ObserveOnMainThread を併用してください。

観点SubscribeOnMainThreadObserveOnMainThread
変更するものソースへの SubscribeDispose の実行場所OnNext / OnErrorResume / OnCompleted の実行場所
主な用途購読開始時に Unity API を触る処理を Unity メインスレッドで開始するGameObject / Component / UI の更新を Unity メインスレッドで行う
Subscribe(...) 内のラムダに効くか直接は効かない効く
Unity オブジェクト更新に必要かこれだけでは不十分多くの場合こちら

SubscribeOnMainThread は、名前から「Subscribe(x => ...) の中身を Unity メインスレッドで実行する」と誤解されやすいですが、そうではありません。SubscribeOnMainThread が動かすのは、ソース Observable に対する購読開始処理です。OnNext を受け取る場所や、Subscribe に渡したラムダの実行場所を変えたい場合は ObserveOnMainThread を使います。

csharp
// 誤解しやすい例: transform 更新がメインスレッドで行われる保証にはならない
observable
    .SubscribeOnMainThread()
    .Subscribe(x => transform.position = x)
    .AddTo(this);

Unity オブジェクトや UI を更新したい場合は、通知を Unity メインスレッドへ戻します。

csharp
observable
    .ObserveOnMainThread()
    .Subscribe(x => transform.position = x)
    .AddTo(this);

SubscribeOnMainThread が有効なのは、購読時点で Unity API に触る Observable です。たとえば購読開始時に GameObject の状態を読む、Unity イベントへ登録する、Component の初期化を行う、といった処理を Unity メインスレッドで開始したい場合に使います。

csharp
Observable.Create<Vector3>(observer =>
    {
        // この購読初期化を Unity メインスレッドで実行したい
        observer.OnNext(transform.position);
        observer.OnCompleted();
        return Disposable.Empty;
    })
    .SubscribeOnMainThread()
    .ObserveOnMainThread()
    .Subscribe(position => positionText.text = position.ToString())
    .AddTo(this);

SubscribeOnMainThread は通常、チェーン内の位置より「ソースへの購読開始」に効きます。一方で、ObserveOnMainThread は置いた位置より下流の通知処理に効きます。Unity オブジェクトを更新したいだけなら、まず ObserveOnMainThread を使う、と覚えると混同しにくくなります。