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();
}

强制同步加载资源

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

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

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

注意:
Unity2020.1版本或者之前,执行该句代码不仅会等待该资源,他会等待所有没有加载完成的异步加载加载完后才会继续往下执行
Unity2020.2版本或以上版本,在加载已经下载的资源时性能影响会好一些
所以,总体来说不建议大家使用这种方式加载资源