
本文将介绍Unity的UniTask取消流程。
如何取消异步方法
首先,看一下如何取消一个异步方法。
对于任务
在写UniTask之前,先总结一下Task,要取消任务,请将CancellationToken传递给异步方法,如下所示:
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
public class Example : MonoBehaviour
{
[SerializeField] private Button _cancelButton;
private async void Start()
{
// 生成CancellationTokenSource
var cts = new CancellationTokenSource();
_cancelButton.onClick.AddListener(() =>
{
cts.Cancel();
});
// 将 CancellationTokenSource.Token 传递给异步方法
await ExampleAsync(cts.Token);
}
private async Task ExampleAsync(CancellationToken cancellationToken = default)
{
// 如果此时取消则抛出 OperationCanceledException 的方法
cancellationToken.ThrowIfCancellationRequested();
for (var i = 0; i < 5; i++) {
// 您可以将 cancellationToken 传递给 Task 工厂方法
await Task.Run(() => Thread.Sleep(1000), cancellationToken);
}
}
}
如果取消,会抛出异常,所以处理一下。
对于UniTask
在UniTask的情况下,取消处理基本上与Task相同。
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
public class Example : MonoBehaviour
{
[SerializeField] private Button _cancelButton;
private async void Start()
{
// 生成CancellationTokenSource
var cts = new CancellationTokenSource();
_cancelButton.onClick.AddListener(() =>
{
cts.Cancel();
});
// 将 CancellationTokenSource.Token 传递给异步方法
await ExampleAsync(cts.Token));
}
private async UniTask ExampleAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
for (var i = 0; i < 5; i++) {
await Task.Run(() => Thread.Sleep(1000), cancellationToken);
}
}
}
Unity的AsyncOperation系统
UniTask在Unity的AsyncOperation结构中实现了GetAwaiter(),但是CancellationToken 不能作为这些的参数传递。
它们具有下面定义的名为WithCancellation()的扩展方法,因此使用它来传递CancellationToken。
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class Example : MonoBehaviour
{
[SerializeField] private Button _cancelButton;
private async void Start()
{
// 生成CancellationTokenSource
var cts = new CancellationTokenSource();
_cancelButton.onClick.AddListener(() =>
{
cts.Cancel();
});
// 将 WithCancellation 传递给那些在 Unity 的 AsyncOperation 中定义的 Awaiter
await UnityWebRequest.Get("http://www.i3dtt.com").SendWebRequest().WithCancellation(cts.Token);
}
}
链接到GameObject生命周期的CancellationToken
使用UniTask,可以获得与GameObject的生命周期关联的CancellationToken。通过将其传递给异步方法,可以实现一个在GameObject被销毁后将被取消的过程。
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Example : MonoBehaviour
{
private async void Start()
{
// 生成一个 CancellationToken,当 GameObject 被销毁时将被取消
await ExampleAsync(this.GetCancellationTokenOnDestroy());
}
private async UniTask ExampleAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
for (var i = 0; i < 5; i++) {
await Task.Run(() => Thread.Sleep(1000), cancellationToken);
}
}
}
如何处理取消
接下来,总结一下如何处理取消异步方法。
基本上是尝试捕捉
取消异步方法时OperationCanceledException会抛出异常,Task和UniTask基本上都是通过try-catch来处理这个异常的。
using System;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Example : MonoBehaviour
{
private async void Start()
{
try
{
await ExampleAsync(this.GetCancellationTokenOnDestroy());
}
catch (OperationCanceledException e)
{
// 捕获OperationCanceledException并处理取消
Debug.Log("它被取消了");
throw;
}
}
private async UniTask ExampleAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
for (var i = 0; i < 5; i++) {
await Task.Run(() => Thread.Sleep(1000), cancellationToken);
}
}
}
使用SuppressCancellationThrow获取取消状态作为返回值
在UniTask的情况下,可以使用以下方法UniTask.SuppressCancellationThrow()接收取消状态作为返回值。
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Example : MonoBehaviour
{
private async void Start()
{
// SuppressCancellationThrow 返回取消状态作为返回值
var canceled = await ExampleAsync(this.GetCancellationTokenOnDestroy()).SuppressCancellationThrow();
if (canceled)
{
Debug.Log("它被取消了");
}
}
private async UniTask ExampleAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
for (var i = 0; i < 5; i++) {
await Task.Run(() => Thread.Sleep(1000), cancellationToken);
}
}
}
…
以上是关于UniTask的取消流程的全部内容,如果你有任何反馈,请随时在本页面下方留言。