跳到主要内容
版本:3.0.x

[扩展] 自定义异步操作

通过CustomAsyncOperation把业务自定义的异步流程交给YooAsset的调度器驱动。

当业务需要把多个异步步骤合并成一个整体流程(例如批量加载一组资源、等待多个句柄后再统一处理),可以直接继承CustomAsyncOperation,由YooAsset的调度系统负责它的启动、每帧更新和终止。

适用场景​

  1. 把多个资源句柄的加载过程合并成一个可以被yield return等待的操作。
  2. 需要参与YooAsset时间切片调度的长流程,避免单帧卡顿。
  3. 需要和包裹生命周期绑定的操作,例如包裹销毁时自动中止。

编写自定义操作​

继承CustomAsyncOperation,并实现InternalStart()和InternalUpdate()两个抽象方法。

public class LoadTextOperation : CustomAsyncOperation
{
private readonly string _location;
private AssetHandle _handle;

/// <summary>
/// 加载成功的文本内容
/// </summary>
public string Text { get; private set; }

public LoadTextOperation(string location)
{
_location = location;
}
protected override void InternalStart()
{
// 发起异步加载
_handle = YooAssets.GetPackage("DefaultPackage").LoadAssetAsync<TextAsset>(_location);
}
protected override void InternalUpdate()
{
// 等待加载结束,期间上报进度
if (_handle.IsDone == false)
{
Progress = _handle.Progress;
return;
}

// 处理加载结果
if (_handle.Status == EOperationStatus.Succeeded)
{
Text = (_handle.AssetObject as TextAsset).text;
SetResult();
}
else
{
SetError(_handle.Error);
}
}
protected override void InternalDispose()
{
// 统一的清理入口,成功、失败和中止都会执行
_handle?.Release();
}
}

编写时需要注意以下几点:

  1. InternalStart()只负责发起异步请求,不要写阻塞逻辑,真正的等待交给InternalUpdate()分帧推进。
  2. 用SetResult()标记操作成功,用SetError(string)标记操作失败,两者都会结束操作并触发完成回调。操作结束之后不能再调用,否则会抛出异常。
  3. Progress的取值范围是0-1,赋值后YooAsset会自动同步给外部的等待者。
  4. InternalDispose()是统一的清理入口,无论操作是成功、失败还是被中止都会执行,资源句柄的释放应该写在这里。
  5. 上面示例返回的是string值,释放句柄不会影响调用方。如果操作需要返回资源对象本身,就要明确句柄的所有权:要么在InternalDispose()里释放,并保证调用方只在操作存活期间使用该对象;要么把句柄一起交给调用方,由调用方负责释放。

提交到调度器​

自定义操作创建之后,需要提交给YooAsset的调度器才会被执行。有两种调度器可以选择:

// 方式一:提交到全局调度器
var operation = new LoadTextOperation("Assets/Res/config.txt");
YooAssets.StartOperation(operation);
yield return operation;
Debug.Log(operation.Text);

// 方式二:提交到包裹的调度器
var package = YooAssets.GetPackage("DefaultPackage");
package.StartOperation(operation);
yield return operation;
Debug.Log(operation.Text);

两者的区别:

  1. 全局调度器不依赖任何包裹,操作在YooAsset初始化完成之后就可以提交。
  2. 包裹调度器上的操作会绑定包裹的生命周期,包裹被移除时操作会被自动中止。

注意事项:

  1. YooAssets.StartOperation()会检测YooAsset的初始化状态,未初始化时调用会抛出异常。
  2. 提交过的操作不要重复提交,同一个操作实例只应该提交一次。
  3. 自定义操作支持协程等待(yield return operation)和异步等待(await operation),也支持WaitForCompletion()同步等待。

参考示例​

扩展工程里提供了多个现成的自定义操作范例,包括按资源标签批量加载资源和获取缓存大小:

Extension/Runtime/ExtensionOperation