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("A"))
    .Delay(TimeSpan.FromSeconds(1f))
    .Do(_ => Debug.Log("B"))
    .Subscribe(_ => Debug.Log("Hello"));

结果:打印B -> 打印A -> 打印Hello

这和我们第一个例子的结果是一样的,大家可以对比来看看。

它的主要作用就是在一些需要流操作的地方,将普通的方法转换为流,算是流的一个基石。



猜你喜欢

转载自blog.csdn.net/u012632851/article/details/80153149