えんじにあ雑記!

開発していて学んだことをまとめていきます!

別スレッドからUIを操作しようとして引っかかった話

UnityでUniTaskを使って非同期処理を実装している際に、別スレッドからUIを操作しようとしてしまいエラーが出てはまったときの対応メモです。

エラー内容

UnityException: get_isActiveAndEnabled can only be called from the main thread.

状況

MVPアーキテクチャで開発しているゲームのモデルクラスで別スレッドでデータのロードをしていました。

public async UniTask<SampleModel> LoadAsync() {
    // なんか処理
    await UniTask.SwitchToThreadPool();
    // なんか処理
    return this;
}

って感じの実装でモデルクラスからデータをロードしていました。

そしてこのモデルクラスに下記のようなバインドをしていました。

SampleModel.Observable
    .Subscribe(model => {
        view.SetView(model.Result);
    }).AddTo(gameObject);

すると、このUI操作部分で

UnityException: get_isActiveAndEnabled can only be called from the main thread.

というエラーが出ました。

原因

モデルクラスの実行スレッドがメインスレッドではなくなっているため、それにバインドしたメソッドも別スレッドから呼び出されてしまい、結果的にメインスレッド以外からuGUIを操作しようとしたことが原因でした。

対応

SampleModel.Observable
    .ObserveOnMainThread()
    .Subscribe(model => {
        view.SetView(model.Result);
    }).AddTo(gameObject);

このようにObserveOnMainThreadを使うことでメインスレッド上で動かすことができるようになり、エラーを解決できました。