UniTaskManager

2 阅读4分钟

概述(Overview)

UniTaskManager 是一个全局异步任务管理器,用于统一管理 Unity 项目中基于 UniTask 的异步操作及其取消逻辑。

核心设计目标:

  • 为每个异步任务分配唯一标识(int ID 或 string key)
  • 支持创建、取消、查询任务
  • 提供统一取消所有任务的能力(常用于返回主菜单、退出场景、清理状态时)
  • 支持 CancellationToken 安全传递,避免异步任务在场景切换或物体销毁后继续运行
  • 内置调试日志开关,便于开发时跟踪任务状态

典型使用场景

  • 引导流程、加载动画、计时器、动画序列
  • 需要中途取消的长时间异步操作(如网络请求、文件读取、动画等待)
  • 场景切换时统一清理所有异步任务
  • 防止异步任务在物体销毁后继续执行导致错误

核心数据结构

  • Dictionary<int, CancellationTokenSource>:ID 任务映射
  • Dictionary<string, CancellationTokenSource>:字符串 key 任务映射

方法一览(API Index)

方法名类型异步返回类型主要功能典型用途
CreateIdTaskstatic(int id, CancellationTokenSource cts)创建一个带唯一自增 ID 的新任务临时、匿名异步任务
CreateStrTaskstatic(string key, CancellationTokenSource cts)创建/替换一个带自定义字符串 key 的任务有语义的任务(如 "LoadScene"、"FadeIn")
CancelIdTaskstaticvoid取消并销毁指定 ID 的任务单个任务中断
CancelStrTaskstaticvoid取消并销毁指定 key 的任务按业务名称取消
CancelAllTasksstaticvoid取消并销毁所有任务(ID + Str)场景切换、返回主菜单、清理状态
HasIdTask / HasStrTaskstaticbool检查任务是否存在判断任务是否在运行
GetTokenById / GetTokenByStrstaticCancellationToken获取任务的 CancellationToken(不存在返回 None)传递给 UniTask 方法
SetVerbosestaticvoid开启/关闭调试日志开发调试
SetDelaystaticUniTask延时指定秒数(支持取消)简洁等待
SetFramestaticUniTask延时指定帧数(支持取消)等待特定帧数
NextFramestaticUniTask等待下一帧(支持取消)确保下一帧执行

方法详情

创建任务

CreateIdTask

/// <summary>
/// 创建一个基于自增 ID 的新异步任务,返回 ID 和 CancellationTokenSource
/// ID 从 0 开始递增,适合临时任务
/// </summary>
/// <returns>(任务唯一 ID, 对应的 CancellationTokenSource)</returns>
public static (int id, CancellationTokenSource cts) CreateIdTask()

用法

var (id, cts) = UniTaskManager.CreateIdTask();
await DoSomethingAsync(cts.Token);
// 完成后可手动取消:UniTaskManager.CancelIdTask(id);

CreateStrTask

/// <summary>
/// 创建一个基于字符串 key 的任务
/// 若已存在同名 key,则先取消并销毁旧任务,再创建新任务
/// </summary>
/// <param name="key">任务的唯一字符串标识(如 "LoadScene"、"FadeUI")</param>
/// <returns>(key, CancellationTokenSource)</returns>
public static (string key, CancellationTokenSource cts) CreateStrTask(string key)

用法

var (key, cts) = UniTaskManager.CreateStrTask("Loading");
await LoadSceneAsync(cts.Token);
// 随时可取消:UniTaskManager.CancelStrTask("Loading");

取消任务

CancelIdTask / CancelStrTask

/// <summary>
/// 取消并销毁指定 ID 的任务
/// </summary>
public static void CancelIdTask(int id)

/// <summary>
/// 取消并销毁指定 key 的任务
/// </summary>
public static void CancelStrTask(string key)

CancelAllTasks

/// <summary>
/// 取消并销毁当前所有异步任务(ID + Str)
/// 常用于返回主菜单、退出场景、清理状态时调用
/// </summary>
public static void CancelAllTasks()

推荐调用时机

  • OnDestroy / OnDisable(当前物体销毁时)
  • 返回主菜单按钮点击
  • 场景切换前

查询与令牌获取

HasIdTask / HasStrTask

public static bool HasIdTask(int id)
public static bool HasStrTask(string key)

GetTokenById / GetTokenByStr

/// <summary>
/// 获取指定 ID 任务的 CancellationToken(不存在返回 CancellationToken.None)
/// </summary>
public static CancellationToken GetTokenById(int id)

/// <summary>
/// 获取指定 key 任务的 CancellationToken
/// </summary>
public static CancellationToken GetTokenByStr(string key)

典型用法

var token = UniTaskManager.GetTokenByStr("Loading");
await UniTask.Delay(5000, cancellationToken: token);

延时辅助方法

SetDelay / SetFrame / NextFrame

/// <summary>
/// 延时指定秒数(支持取消)
/// </summary>
public static async UniTask SetDelay(double time, CancellationToken ctk)

/// <summary>
/// 延时指定帧数
/// </summary>
public static async UniTask SetFrame(int time, CancellationToken ctk)

/// <summary>
/// 等待下一帧
/// </summary>
public static async UniTask NextFrame(CancellationToken ctk)

推荐替代:await UniTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: ctk);


使用建议与最佳实践

  1. 创建任务

    • 临时任务用 CreateIdTask()
    • 有业务含义的任务用 CreateStrTask("xxx")(便于阅读和取消)
  2. 传递 Token 所有异步方法都应接收 CancellationToken:

    await DoSomethingAsync(cts.Token);
    
  3. 取消处理 在异步方法中捕获 OperationCanceledException:

    try
    {
        await LoadDataAsync(cts.Token);
    }
    catch (OperationCanceledException)
    {
        Debug.Log("任务被取消");
    }
    
  4. 统一清理 在返回主菜单、退出场景、物体销毁时调用:

    UniTaskManager.CancelAllTasks();
    
  5. 调试 开启日志查看任务创建/取消:

    UniTaskManager.SetVerbose(true);
    
  6. 注意事项

    • CancellationTokenSource 本身不负责停止协程或 UniTask,必须手动传递 Token
    • 销毁物体后仍需手动取消对应任务,否则可能出现空引用
    • 大量任务时,建议在 CancelAllTasks 后检查是否全部清理干净