| 第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则是对这些提供了这些管理手段。 异步处理和UniRxUniRx由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。 UniTaskUniTask是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消息发行后会停止一段时间, |