天天看點

Unity3D UniRx ReactiveX響應式程式設計2 常用方法總結

環境:Unity2017.2 語言:C#

總起:

在正式講UniRx技術之前,首先推薦一篇老外寫的入門文章:https://zhuanlan.zhihu.com/p/27678951。

看了以上文章後,應該會對UniRx用來做什麼有一定了了解了。而我今天就将我這幾天使用的幾種常用方法列舉一下,供大家編寫程式時參考。

個人非常喜歡Rx這種流式的程式設計方式,不過這種技術資料比較少,大家如果有相關文檔什麼的,歡迎共享!

我個人總結了一下Rx的作用:在Unity中就是準備把Update中複雜的ifelse語句全部删除,全部寫到Start中,然後所有ifelse邏輯通過流的組合來實作。

常用方法:

♦ 流的順序執行

IEnumerator CorA()
{
    yield return new WaitForSeconds(1f);
    Debug.Log("A");
}

IEnumerator CorB()
{
    yield return new WaitForSeconds(1f);
    Debug.Log("B");
}

void Start ()
{
	var StreamA = Observable.FromCoroutine(CorA);
	var StreamB = Observable.FromCoroutine(CorB);
	StreamA.SelectMany(StreamB)
        .Subscribe(_=>Debug.Log("Hello"));
}
           

通過Observable.FromCoroutine方法将協程轉換為了流,然後通過SelectMany方法将流A和流B組合起來,達到先執行A後,執行完A後執行B的效果,最後全部執行完執行Hello。

結果:列印A -> 列印B -> 列印Hello

然後我們來看另一種寫法:

void Start ()
{
	var StreamA = Observable.FromCoroutine(CorA);
	var StreamB = Observable.FromCoroutine(CorB);
	StreamA.Concat(StreamB)
        .Subscribe(_=>Debug.Log("Hello"));
}
           

使用Concat方法,同樣也是順序連接配接A和B,但是結果有些不一樣。

結果:列印A -> 列印Hello -> 列印B -> 列印Hello

為什麼會出現這樣的情況?

首先我稍微提一下Rx的内部實作細節:内部有兩種方法OnNext和OnComplete(暫時不考慮OnError),OnComplete調用的時候就是整個流生命周期完結的時候,而OnNext是往下進行通知。比方說一段流SubScribe列印Hello,流中每次執行OnNext就會列印一次Hello。也就是平時說的事件觸發就會調用OnNext。

知道了OnNext的作用後,StreamA和StreamB執行完協程後都會發出一次OnNext,是以Concat連接配接後OnNext繼續向下傳遞,是以會列印兩次Hello。

而SelectMany會屏蔽之前所有的OnNext,直到最後一個協程執行完畢,才會繼續傳遞OnNext,是以最終隻有一次。當然SelectMany是最常用的。

♦ 流的同步執行

IEnumerator CorA()
{
    yield return new WaitForSeconds(2f);
    Debug.Log("A");
}

IEnumerator CorB()
{
    yield return new WaitForSeconds(1f);
    Debug.Log("B");
}

void Start ()
{
	var StreamA = Observable.FromCoroutine(CorA);
	var StreamB = Observable.FromCoroutine(CorB);
    Observable.WhenAll(StreamA, StreamB)
        .Subscribe(_=>Debug.Log("Hello"));
}
           

結果:列印B -> 列印A -> 列印Hello

Observable.WhenAll等待傳入所有的流全部執行完畢後執行下面的操作。

♦ 延時執行

Observable.Timer(TimeSpan.FromSeconds(1f))
    .Subscribe(_ => Debug.Log("Hello"));
           

結果:一秒之後列印Hello

StreamA.Delay(TimeSpan.FromSeconds(1f))
    .Do(_=>Debug.Log("立即執行"))
.Subscribe(_ => Debug.Log("Hello"));
           

結果:列印A -> 等待1秒 -> 列印立即執行 -> 列印Hello

Timer用于建立一個延時的流,在等待相應的時間後會發出一次OnNext。

而Delay則是流調用的一個方法,将發出的OnNext延時一個時間。

這邊的Do方法,就是擷取到OnNext後,馬上執行Do中的内容,并将OnNext傳遞下去。

♦ 空流

不管是在什麼語言工具中,一個空的概念是很重要的。而空流則是Rx中空的概念,所有的流都是基于這個概念而來的。

實際的來說Observable.ReturnUnit()就能産生一個空流,它的作用就是直接産生一個OnNext向後執行。

一個示例:

Observable.ReturnUnit()
    .Delay(TimeSpan.FromSeconds(1f))
    .Do(_ => Debug.Log("B"))
    .Delay(TimeSpan.FromSeconds(1f))
    .Do(_ => Debug.Log("A"))
    .Subscribe(_ => Debug.Log("Hello"));
           

結果:列印B -> 列印A -> 列印Hello

這和我們第一個例子的結果是一樣的,大家可以對比來看看。

它的主要作用就是在一些需要流操作的地方,将普通的方法轉換為流,算是流的一個基石。