UniRx入门总结
- 什么是UniRx?
- 为什么要使用UniRx?
- 常用API
- 定时功能
- Update
- 操作符 First
- 操作符Where
- ReactiveProperty
- 对UGUI的支持
- 操作符Merge
什么是UniRx?
UniRx就是Unity版本的Reactive Extensions,Reactive Extensions 中文意思是:响应式扩展,响应式指的是观察者和定时器,扩展指的是 LINQ的操作符。Reactive Extensions以擅长处理时间上异步的逻辑、以及极简的API风格慕名而来。
为什么要使用UniRx?
因为很多在项目上的一些逻辑操作都需要在时间上异步处理,所以需要实现的异步逻辑往往会比较多。这也是为什么会有携程的概念。
在项目中,像动画的播放、网络请求、资源加载、场景过度等等都是在时间上异步操作的逻辑,当我们在项目上实现上述功能模块时,往往使用通过大量的回调实现,可能会导致项目充斥着大量的回调来处理某些逻辑,相对较好的方法则是实用消息/事件进行实现,但是结果也可能导致项目中有大量的事件,经过一段时间可能看不明白自己写的逻辑。
而UniRx的出现刚好解决解决了这个问题,它介于回调和事件之间。
- 它有事件的概念,只不过它的事件是像流水一样,我们在开发过程中需要对这些事件进行组织、变换、过滤、合并等操作
- 它也用了回调,只不过它的回调是在事件经过组织之后,只需要调用一次就进行事件处理了
常用API
定时功能
平常项目中可能经常遇到经过一段时间再触发某些逻辑操作
平常的可能通过使用协程
void Start()
{
StartCoroutine(Timer(10, DoSomething));
}
IEnumerator Timer(float seconds,Action callback)
{
yield return new WaitForSeconds(seconds);
callback();
}
void DoSomething()
{
Debug.Log("TODO");
}
代码声明实现了跟上述一样的功能,经过10s去打印,代码是不是很清晰。
void Start()
{
Observable
.Timer(TimeSpan.FromSeconds(10))
.Subscribe(e => {
Debug.Log("DoSomething");
});
}
还有一点需要注意的是上述写法没有和Unity中的MonoBehaviour进行生命周期绑定,可能MonoBehaviour销毁了之后,逻辑还在执行,可能会造成空指针。 需要在最后加上.AddTo(this)
,当生命周期被销毁,脚本逻辑也会跟随销毁。这也是我们平常写逻辑需要注意的点。
代码如下
void Start()
{
Observable
.Timer(TimeSpan.FromSeconds(10))
.Subscribe(e => {
Debug.Log("DoSomething");
})
.AddTo(this);
}
Update
写功能模块时平常可能在Update中定义某些逻辑,随着项目可能Update中的代码量很大。使用UniRx可以使代码相互独立。如下所示:(注意不要忘记在最后添加.AddTo(this)
)
void Start()
{
Observable
.EveryUpdate()
.Subscribe(e => {
Debug.Log("QQQ");
})
.AddTo(this);
Observable
.EveryUpdate()
.Subscribe(e => {
Debug.Log("WWW");
})
.AddTo(this);
Observable
.EveryUpdate()
.Subscribe(e => {
Debug.Log("EEE");
})
.AddTo(this);
}
上述代码可以在实际项目中通过业务模块的划分将其单独定义,也便于以后的维护。
操作符 First
平常做项目中也可能遇到第一次需要执行后续则不需要执行的相关功能,常规实现我们可能定义一个bool值,在执行一次后将其赋值为false,通过第一次鼠标点击来举例,关键字是First
。代码如下
void Start()
{
Observable
.EveryUpdate()
.First(_=>Input.GetMouseButtonDown(0))
.Subscribe(e => {
Debug.Log("EEE");
})
.AddTo(this);
}
操作符Where
这个Where可以理解为当满足一定条件时才能往下执行。代码如下,当鼠标左键被按下时打印输出。
void Start()
{
Observable
.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Subscribe( _=>
{
Debug.Log("DOSomething");
})
.AddTo(this);
}
ReactiveProperty
ReactiveProperty是响应式属性的意思,顾名思义就是当为项目中某个属性进行赋值会动态执行相关逻辑,直接上代码,下面代码有什么局限性呢,当值改变时,只能在属性内部进行对应方法响应,如果我想在外部进行调用呢?那可能需要定义一个委托进行绑定。UniRx有更简洁的API;
常规写法
private int age;
public int Age
{
get
{
return age;
}
set {
if (value>0)
{
age = value;
OnAgeChanged();
}
}
}
void OnAgeChanged()
{
}
UniRx用法
public ReactiveProperty<int> Age = new ReactiveProperty<int>();
void Start()
{
Age.Subscribe(age =>
{
Debug.Log("赋值之后改变的方法");
});
Age.Value = 22;
}
对UGUI的支持
可以使用UniRx对UI控件进行动态绑定,其余用法可以自行查询。也可以根据业务需求在定义时添加Where
、First
等操作符。
public Button btn;
public Toggle toggle;
void Start()
{
btn.OnClickAsObservable()
.Subscribe(_ =>
{
Debug.Log("BtnClick");
});
toggle.OnValueChangedAsObservable()
.Subscribe(isOn =>
{
if (isOn)
{
}
else
{ }
});
}
操作符Merge
这里介绍的是对UniRx定义的流逻辑进行合并操作,代码如下:代码分别定义了两个事件流,通过操作符Merge进行合并,当鼠标左键或右键按下时,都会打印输出。
void Start()
{
//定义流1
var stream01 = Observable
.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0));
//定义流2
var stream02 = Observable
.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(1));
Observable.Merge(stream01, stream02)
.Subscribe(_ => {
Debug.Log("DoSomeThing");
})
.AddTo(this);
}
基本用法就介绍到这。