環境: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
這和我們第一個例子的結果是一樣的,大家可以對比來看看。
它的主要作用就是在一些需要流操作的地方,将普通的方法轉換為流,算是流的一個基石。