使用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则在上面给到的连接里面下载(两个都要有)。

猜你喜欢

转载自blog.csdn.net/qq_37421018/article/details/103023943