U4S4L16——关于Async Operation Handle

本章代码关键字

1
2
3
4
5
asyncOperationHandle<>.GetDownloadStatus()    //获取当前下载状态的结构体
DownloadStatus //加载状态结构体,获取到加载进度,加载字节数,总字节数
AsyncOperationHandle //无类型的异步操作处理类,AsyncOperationHandle<>可隐式转换为它,也可以转换回去
asyncOperationHandle.Convert<>() //将无类型的异步操作处理类转换为有类型的
asyncOperationHandle<>.WaitForCompletion() //强制同步加载资源

获取加载进度

我们通过调用 AsyncOperationHandle<>.GetDownloadStatus()​ 来获取当前打印状态,返回的是 DownloadStatus​ 结构体数据
通过该结构体我们可以获取到 Percent​ 加载进度(0~1​),DownloadedBytes​ 加载字节数,TotalBytes​ 总字节数

注意:如果该资源相关的 AB 包已经加载过了,那么只会打印 0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void Start()
{
StartCoroutine(LoadAsset());
}

IEnumerator LoadAsset()
{
AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>("Cube");
//注意:如果该资源相关的AB包 已经加载过了 那么 只会打印0
while (!handle.IsDone)
{
DownloadStatus info = handle.GetDownloadStatus();
//加载进度
print("下载进度:" + info.Percent);
//字节加载进度 代表 AB包 加载了多少:当前下载字节数 / 文件总字节数
print("下载字节数:" + info.DownloadedBytes + "/" + info.TotalBytes);
yield return 0;
}
//加载成功后即可使用
if (handle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(handle.Result);
}
else
Addressables.Release(handle);
}

无类型句柄转换

无类型句柄指的是 AsyncOperationHandle​,它不携带类型信息
它在内部通过 implicit operator​ 重载了隐式转换,使得 AsyncOperationHandle<>​ 可以隐式转换为 AsyncOperationHandle

重载了隐式转换运算符的具体用法详见:用户定义的显式和隐式转换运算符 - 提供对不同类型的转换 - C# reference | Microsoft Learn

1
2
3
4
5
//AsyncOperationHandle内部
static public implicit operator AsyncOperationHandle(AsyncOperationHandle<TObject> obj)
{
return new AsyncOperationHandle(obj.m_InternalOp, obj.m_Version, obj.m_LocationName);
}

我们可以将异步加载方法 Addressables.LoadAssetAsync<>()​ 返回的 AsyncOperationHandle<>​ 隐式转换为 AsyncOperationHandle
之后在将无类型的 AsyncOperationHandle​ 转换为有类型的AsyncOperationHandle<>

1
2
3
4
5
6
void Start()
{
AsyncOperationHandle tempHandle = Addressables.LoadAssetAsync<Texture2D>("Cube");
//将 无类型句柄 转换为 有类型的泛型对象
AsyncOperationHandle<Texture2D> handle = tempHandle.Convert<Texture2D>();
}

这种有类型句柄可转换为无类型句柄的特性,可用于统一管理加载出来的不同资源

我们可以使用无类型的 AsyncOperationHandle​ 容器来装载不同泛型类型的 AsyncOperationHandle<>​ 数据

这样,我们不需要使用 AsyncOperationHandle<>​ 的父类或者接口的容器去统一的装载 AsyncOperationHandle<>​ 数据
方便我们对各种 AsyncOperationHandle<>​ 数据执行一些不涉及资源类型信息的操作,例如卸载等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Dictionary<string, AsyncOperationHandle> resDic = new Dictionary<string, AsyncOperationHandle>();

public void Clear()
{
foreach (var handle in resDic.Values)
{
//对不同类型的AsyncOperationHandle<>完成了统一的卸载
Addressables.Release(handle);
}
resDic.Clear();
AssetBundle.UnloadAllAssetBundles(true);
Resources.UnloadUnusedAssets();
GC.Collect();
}

强制同步加载资源

警告!如果项目最终是导出到 WebGL 的,切勿使用此方法,此方法不支持 WebGL 平台上执行!

如果执行了 WaitForCompletion()​,那么会阻塞主线程,一定要当资源加载结束后,才会继续往下执行

注意:如无特殊需求,不建议使用该方法

1
2
3
4
5
6
void Start()
{
AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>("Cube");
handle.WaitForCompletion();
Instantiate(handle.Result);
}

注意!

  • Unity 2020.1 版本或者之前,执行该句代码不仅会等待该资源,他会等待所有没有加载完成的异步加载加载完后才会继续往下执行
  • Unity 2020.2 版本或以上版本,在加载已经下载的资源时性能影响会好一些

所以,总体来说不建议大家使用这种方式加载资源