UniTask キャンセル処理

今回の記事はUniTaskを用いたキャンセル処理についてです.

前回記事

xrdnk.hateblo.jp

こちらのダウンロード処理中にキャンセルを加えてみた.

参考記事

UniTask ver1 時代のもの.UniTask 2でもあまり変わらない.

qiita.com

Model 側

CancellationTokenSource.Cancel()を使う.
UniTaskの処理中にキャンセルされた場合,OperationCanceledExceptionが生じるので,
そこでcatchして,例外処理が起きた時の処理を書く.

using System;
using UnityEngine;
using System.Threading;
using Cysharp.Threading.Tasks; // UniTask 2 から名前空間が UniRx.Async から変更
using UniRx;
using UnityEngine.Networking;

public class ProgressModel : MonoBehaviour
{
    private ReactiveProperty<float> _downloadProgress = new ReactiveProperty<float>();
    public IReadOnlyReactiveProperty<float> DownloadProgress => _downloadProgress;

    // CancellationTokenの設定
    private CancellationToken _token;
    private CancellationTokenSource _tokenSource;

    private UnityWebRequest unityWebRequest;

    private void Awake()
    {
        _tokenSource = new CancellationTokenSource();
        // Destroy時にキャンセルされるCancellationTokenを取得
        _token = _tokenSource.Token;
    }

    public async void DownloadContent()
    {
        // 取得したいコンテンツのURL
        var url = "https://public-cdn.cloud.unity3d.com/hub/prod/UnityHubSetup.dmg";
        // テキストデータの取得
        var textData = await DownloadTextAsync(url);
    }

    public void CancelDownload()
    {
        _tokenSource.Cancel();
    }

    /// <summary>
    /// コンテンツのダウンロード処理
    /// </summary>
    /// <param name="url">URL</param>
    /// <returns>コンテンツのテキストデータ</returns>
    private async UniTask<string> DownloadTextAsync(string url)
    {
        var uwr = UnityWebRequest.Get(url);
        try
        {
            using (uwr)
            {
                // 送受信開始
                await uwr.SendWebRequest()
                            .ToUniTask(Progress.Create<float>(x =>
                                    // 値の変化を設定
                                    _downloadProgress.Value = x * 100),
                                    // cancellationToken: のラベルはつけること
                                    cancellationToken: _token
                                    );
                // エラーハンドリング
                if (uwr.isNetworkError || uwr.isHttpError) throw new Exception(uwr.error);
                // ダウンロードしたコンテンツのテキストデータを返す
                return uwr.downloadHandler.text;
            }
        }
        catch (OperationCanceledException)
        {
            Debug.LogWarning("Canceled!");
            throw;
        }
    }
}

View 側

Cancel用のボタンを追加.

using System; // IObservableの利用に必要
using UnityEngine;
using UnityEngine.UI;
using UniRx;

public class ProgressView : MonoBehaviour
{
    [SerializeField, Tooltip("ダウンロード進捗率表示用のUI")]
    private Text _text_Progress;
    [SerializeField, Tooltip("ダウンロードボタン")]
    private Button _button_Download;
    [SerializeField, Tooltip("Cancelボタン")]
    private Button _button_Cancel;

    private IObservable<Unit> _onDownloadButtonPushed => _button_Download.OnClickAsObservable();
    public IObservable<Unit> OnDownloadButtonPushed => _onDownloadButtonPushed;

    private IObservable<Unit> _onCancelButtonPushed => _button_Cancel.OnClickAsObservable();
    public IObservable<Unit> OnCancelButtonPushed => _onCancelButtonPushed;

    /// <summary>
    /// ダウンロード進捗率を整数表示する
    /// </summary>
    /// <param name="progress"></param>
    public void DisplayProgress(float progress)
    {
        _text_Progress.text = progress.ToString("F0") + " %";
    }
}

Presenter 側

ボタン押下検知時のSubscribe の追加.

using UnityEngine;
using UniRx;

public class ProgressPresenter : MonoBehaviour
{
    // Extenjectを用いる方が良い
    [SerializeField] private ProgressModel _progressModel;
    [SerializeField] private ProgressView _progressView;

    void Start()
    {
        // Viewにあるダウンロードボタンの押下時、Modelに通知する
        _progressView.OnDownloadButtonPushed.Subscribe(_ => _progressModel.DownloadContent());

        // ViewのCancelボタン押下時にModelに通知する
        _progressView.OnCancelButtonPushed.Subscribe(_ => _progressModel.CancelDownload());

        // Modelにある進捗率の値が変化した時、Viewに通知する
        _progressModel.DownloadProgress.Subscribe(_progressView.DisplayProgress);
    }
}

動作確認

gyazo.com キャンセルボタンを押すと止まりました.

gyazo.com