第1章 概述
1.1 UniRx是什么
UniRx是以Reactive Extensions为基础的胃Unity的非同期和事件处理的库。
1.2 UniRx的导入方法
1.21 从 Unity Asset Store 导入
https://assetstore.unity.com/packages/tools/integration/unirx-reactive-extensions-for-unity-17276
1.22 从Github 下载最新的release包 导入
https://github.com/neuecc/UniRx
1.3 UniRx的用途
1.31 异步(非同期)处理
异步处理是什么
当某个处理(函数)在执行的时候,并不等到这个处理结束而去执行别的处理的这种行为叫做【异步处理】,Unity的Coroutine就是异步处理的一种。
异步处理的缺点
想要安全的进行异步处理,以上的一些管理手段都是必要的,UniRx则是对这些提供了这些管理手段。
异步处理和UniRx
UniRx由Observable,Operator,Scheduler这三个部分组成
| 名字 | 用途 |
| ---------- | ------------------------------------------------------ |
| Observable | 异步处理的结果和对这个处理内容的一系列流程的管理的手段 |
| Operator | Observable对复杂的处理进行辅助的手段 |
| Scheduler | Observable对执行Context进行管理的手段 |
UniRx异步处理的使用例子
using System;
using System.Collections;
using UniRx;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
namespace Sample.Section1
{
public class DownloadTexture : MonoBehaviour
{
/// <summary>
/// UGUI 的 RawImage
/// </summary>
[SerializeField] private RawImage _rawImage;
private void Start()
{
//想要表示的画像的address
var url = "https://pbs.twimg.com/media/EVAhiXWUwAQx5oD?format=jpg&name=4096x4096";
//取得Texture
//例外发生时 尝试3回
GetTextureAsync(url)
.OnErrorRetry(
onError: (Exception _) => { },
retryCount: 3
).Subscribe(result => { _rawImage.texture = result; },
error => { Debug.Log(error); })
.AddTo(this);
}
/// <summary>
/// 启动Coroutine,并把结果用 Observable返回
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private IObservable<Texture> GetTextureAsync(string url)
{
return Observable.FromCoroutine<Texture>(observer =>
{
return GetTextureCoroutine(observer, url);
});
}
/// <summary>
/// 用Coroutine进行图片下载
/// </summary>
/// <param name="observer"></param>
/// <param name="url"></param>
/// <returns></returns>
private IEnumerator GetTextureCoroutine(IObserver<Texture> observer, string url)
{
using (var uwr = UnityWebRequestTexture.GetTexture(url))
{
yield return uwr.SendWebRequest();
if (uwr.result == UnityWebRequest.Result.ConnectionError
|| uwr.result == UnityWebRequest.Result.ProtocolError)
{
//Error发生时 发送 OnError 消息
observer.OnError(new Exception(uwr.error));
yield break;
}
var result = ((DownloadHandlerTexture) uwr.downloadHandler).texture;
//成功时 发送OnNext/OnCompleted消息
observer.OnNext(result);
observer.OnCompleted();
}
}
}
}
GetTextureCoroutine方法,使用Coroutine对从指定的url下载Texture,并通过用UniRx(Observable) 来对不同的结果进行返回。
GetTextureCoroutine(IObserver<Texture> observer, string url)
{
using (var uwr = UnityWebRequestTexture.GetTexture(url))
{
yield return uwr.SendWebRequest();
if (uwr.result == UnityWebRequest.Result.ConnectionError
|| uwr.result == UnityWebRequest.Result.ProtocolError)
{
//Error发生时 发送 OnError 消息
observer.OnError(new Exception(uwr.error));
yield break;
}
var result = ((DownloadHandlerTexture) uwr.downloadHandler).texture;
//成功时 发送OnNext/OnCompleted消息
observer.OnNext(result);
observer.OnCompleted();
}
}
}
}
GetTextureAsync方法,则是把Coroutine变化成Observable
/// <summary>
/// 启动Coroutine,并把结果用 Observable返回
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private IObservable<Texture> GetTextureAsync(string url)
{
return Observable.FromCoroutine<Texture>(observer =>
{
return GetTextureCoroutine(observer, url);
});
}
然后就是Start方法里,订阅由GetTextureAsync方法生成的Observable,OnErrorRetry 是 Operator中的1种,可以对出错时的处理和再处理进行指定,Subscribe()是Observable的用来接受Observable的函数,结果发行的时候,订阅的函数会被执行
private void Start()
{
//想要表示的画像的address
var url = "https://pbs.twimg.com/media/EVAhiXWUwAQx5oD?format=jpg&name=4096x4096";
//取得Texture
//例外发生时 尝试3回
GetTextureAsync(url)
.OnErrorRetry(
onError: (Exception _) => { },
retryCount: 3
).Subscribe(result => { _rawImage.texture = result; },
error => { Debug.Log(error); })
.AddTo(this);
}
像这样,UniRx把异步处理变成Observable,之后可以通过链式方法进行复杂的处理,和别的一步处理并行,处理结束后进行别的异步处理都可以。
和async/await比较
UniRx可以使用链式进行复杂的处理,但是简单的异步处理反而会显得很冗长,这是他的缺点,
现在 Unity可以使用C#7.3/.NET Standard2.0 的API,可以使用async/await。这个async/await 可以像同步处理一样写异步处理,所以简单的异步处理使用async/await场合更多,而不是UniRx。
UniTask
UniTask是UniRx的姐妹库一样的存在,对Unity的Async/Await进行了强化的库
上面的例子可以和UniTask并用
using System;
using System.Collections;
using System.Threading;
using Cysharp.Threading.Tasks;
using UniRx;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
namespace Sample.Section1.Async
{
/// <summary>
/// 下载指定的图片
/// 设定到rawImage
/// </summary>
public class DownloadTextureUniTask : MonoBehaviour
{
/// <summary>
/// UGUI 的 RawImage
/// </summary>
[SerializeField] private RawImage _rawImage;
private void Start()
{
//取得 跟这个GameObject绑定的CancellationToken
var token = this.GetCancellationTokenOnDestroy();
//设置图片
SetupTextureAsync(token).Forget();
}
private async UniTaskVoid SetupTextureAsync(CancellationToken token)
{
try
{
//想要表示的画像的address
var url = "https://pbs.twimg.com/media/EVAhiXWUwAQx5oD?format=jpg&name=4096x4096";
//想要使用UniRx的Retry,把UniRX变成 IObservable
var observable = Observable
.Defer(() =>
//UniRx -> IObservable
GetTextureAsync(url, token).ToObservable()).Retry(3);
//Observable 也可以使用await
var texture = await observable;
_rawImage.texture = texture;
}
catch (Exception e)when (!(e is OperationCanceledException))
{
Debug.LogError(e);
}
}
//使用async/await 代替 Coroutine
private async UniTask<Texture> GetTextureAsync(string url, CancellationToken token)
{
using (var uwr = UnityWebRequestTexture.GetTexture(url))
{
await uwr.SendWebRequest().WithCancellation(token);
return ((DownloadHandlerTexture) uwr.downloadHandler).texture;
}
}
}
}
1.32 事件处理的利用
事件处理是当条件满足时发行事件消息,接受消息的一边会执行。
Unity开发会经常使用到各种事件。
事件处理和UniRx
UniRx提供Observable,很擅长对事件进行处理
而且Operator非常强力,复杂的事件处理可以简单的写出来。
UniRx事件处理的使用例
using System;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
namespace Sample.Section1
{
public class ThrottleButton : MonoBehaviour
{
private void Start()
{
//Update()每一帧对Fire Btn 有没有被按下进行判定
//按下了就调用Subscribe对处理
//然后无视30帧
this.UpdateAsObservable()
.Where(_ => Input.GetButtonDown("Fire1"))
.ThrottleFirstFrame(30)
.Subscribe(_ =>
{
Debug.Log("Fire");
});
}
}
}
UniRx的UpdataAsObservable() 可以把Undate()转化为Observable的消息。
ThrottleFirstFrame 是当OnNext消息发行后会停止一段时间,
|