使用UniRx加UniRx.Async實現AddressableReference的異步加載

因爲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則在上面給到的連接裏面下載(兩個都要有)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章