因爲Addressable資源的加載是異步進行的,而一般的寫法是添加回調,如下是一種寫法:
public static void LoadAsync<T>(string address, UnityAction<AsyncOperationHandle<T>> endCb)
{
Addressables.LoadAssetAsync<T>(address).Completed() += endCb;
}
另外可以使用await/async來實現:
public static async Task<T> LoadAsync<T>(string address)
{
var handle = Addressables.LoadAssetAsync<T>(address);
await handle.Task;
return handle.Result;
}
但是這種實現方式會出現一個情況,就是當我按如下兩種方式去實現的時候,結果是不一樣的:
private void Start()
{
m_Sprite = LoadAsync<Sprite>("ssss");
SetSprite();
}
private async void SetSprite()
{
var task = LoadAsync<Sprite>("ssss");
await task;
m_Sprite = task.Result;
}
當函數執行到第3行時會卡死,因爲這裏它認爲需要等待一個數據來獲取,然而task一直也沒有返回數據,所以程序卡死,Unity崩潰,而只用採用第4行的方式才能夠正常獲取,但這就意味着你得寫很多層嵌套才能真正處理好數據獲取(採用回到也大同小異)所以這個時候我就想到了用UniRx來處理這個異步編程。
UniRx是什麼這裏就不說了,UniRx.Async是官方爲了支持C#新特性await/aysnc而拓展的異步邏輯,裏面也使用了一個類似於Task的UniTask,但是功能卻豐富得多,而且UniTask有個ToObserveable的方法,使用它可以做到很輕鬆的異步處理:
public async UniTask<T> LoadAsync<T>(string address)
{
var handle = Addressables.LoadAssetAsync<T>(address);
await handle.Task;
return handle.Result;
}
private void Start(){
var task = LoadAsync<Sprite>("ssss");
task.ToObservable().Subscribe(res => { image.sprite = res; });
}
可以看到UniTask本身的寫法與Task無異,使用這種方法我們可以不用寫大量的異步或者回調,當LoadAsync執行完畢後即會調用Subscribe裏面的方法,效率方面我沒有研究,不過根據官方及民間數據的調查來看應該不錯,我看過的雨凇Mono大佬的文章裏面也提到過它的好處。更多的資料請去官網插看:https://github.com/Cysharp/UniTask#license UniRx本身在UnityAssetStore上面就能下載,UniRx.Async則在上面給到的連接裏面下載(兩個都要有)。