Reactive X 是 Reactive Extensions 的缩写,一般简写为 Rx,最初是 LINQ 的一个扩展,由微软的团队开发,Rx 是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,支持大部分流行语言。
Rx是一个函数库,让开发者可以利用可观察序列和 LINQ 风格查询操作符来编写异步和基于事件的程序,使用Rx,开发者可以用Observables 表示异步数据流,用 LINO 操作符查询异步数据流,用 Schedulers 参数化异步数据流的并发处理,Rx可以这样定义︰
Rx = Observables + LINQ + Schedulers
Rx 结合了观察者模式、迭代器模式和函数式编程的精华。UniRx 就是 Unity Reactive Extensions,是为 Unity 平台设计的响应式编程框架。
在游戏中,⼤部分的逻辑都是在时间上异步的。⽐如动画的播放、声⾳的播放、⽹络请求、资源加载/卸载、场景过渡等。
在实现 异步逻辑时经常⽤到⼤量的回调,最终随着项⽬的扩张导致传说中的”回调地狱”。
相对较好地⽅法则是使⽤消息/事件的发送,结果导致“消息满天⻜”,导致代码⾮常难以阅读。
⽽ UniRx 的出现刚好解决了这个问题,它介于回调和事件之间。
常用API
监听 mono 生命周期函数
Observable.EveryUpdate() // 开启 Update 的事件监听
.Subscribe(_ => // 订阅/处理事件
{
Debug.Log("Update");
});
Observable.EveryLateUpdate()
.Subscribe(_ =>
{
Debug.Log("LateUpdate");
});
Observable.EveryFixedUpdate()
.Subscribe(_ =>
{
Debug.Log("FixedUpdate");
});
Observable.EveryEndOfFrame()
.Subscribe(_ =>
{
Debug.Log("EndOfFrame");
});
Observable.EveryApplicationFocus()
.Subscribe(focuse =>
{
Debug.Log("Focus: " + focuse);
});
如果在 Update ⽅法中,除了实现⿏标事件监听这个功能之外,还要实现其他的功能。那么 Update ⾥就会充斥着⼤量的状态判断等逻辑。代码⾮常不容易阅读。
⽽ UniRx 提供了⼀种编程思维,使得平时⼀些⽐较难实现的异步逻辑,使⽤ UniRx 轻松搞定,并且不失代码的可读性
参数下划线 _ 表示帧数,这里用不到就用 _ 表示
Timer 定时
Observable.Timer(TimeSpan.FromSeconds(5.0f))
.Subscribe(_ =>
{
Debug.Log("do something");
});
Interval 间隔
Observable.Interval(TimeSpan.FromSeconds(1))
.Subscribe(time => Debug.Log(time));
AddTo 与 Trigger
Observable.Timer(TimeSpan.FromSeconds(2.0f))
.Subscribe(_ =>
{
Debug.Log("延时两秒");
})
.AddTo(this);
this.OnDestroyAsObservable()
.Subscribe(_ =>
{
Debug.Log("OnDestroy");
});
this.OnCollisionEnterAsObservable()
.Subscribe(collision =>
{
Debug.Log("CollisionEnter");
});
AddTo 会在 GameObject 上添加一个 ObservableDestroyTrigger 脚本监听它的 OnDestroy 事件,当 GameObject 销毁时也会销毁正在运行的 UniRx 任务,即 GameObject 销毁时,这个 Timer 也会销毁,避免空引用异常。
ObservableDestroyTrigger 是一个 Trigger,Trigger 大部分都是都是 XXXAsObsrevable 命名形式的。
在使用 Trigger 的 GameObject 上都会挂上对应的 ObservableXXXTrigger 的脚本,AddTo 这个 API 就是封装了 ObservableDestroyTrigger
Where,First 过滤
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0)) //进行一个鼠标是否点击的判断
.First() //只获取第一次点击事件
.Subscribe(_ =>
{
Debug.Log("left mouse clicked");
});
//也可以写成这样
Observable.EveryUpdate()
.First(_ => Input.GetMouseButtonDown(0)) //只获取第一次点击事件
.Subscribe(_ =>
{
Debug.Log("left mouse clicked");
});
EveryUpdate 是事件的发布者。他会每帧会发送⼀个事件过来。
Subscribe 是事件的接收者,接收的是 EveryUpdate 发送的事件。
Where 则是在事件的发布者和接收者之间的⼀个过滤操作。会过滤掉不满⾜条件的事件
First 又进行了一个过滤
Merge
在 UniRx 世界中,任何东西都是以事件流的形式存在,EveryUpdate 和 Timer 都是开启一条事件流。UniRx 可以开启多条事件流,然后使用 Merge 合并。
var leftClickEvents = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0));
var rightClickEvents = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(1));
//点击左键或右键都会触发
Observable.Merge(leftClickEvents, rightClickEvents)
.Subscribe(_ =>
{
Debug.Log("mouse clicked");
});
WhenAll
当所有事件流都结束后触发
IEnumerator A()
{
yield return new WaitForSeconds(1.0f);
Debug.Log("A");
}
IEnumerator B()
{
yield return new WaitForSeconds(2.0f);
Debug.Log("B");
}
void Start()
{
var aStream = Observable.FromCoroutine(_ => A());
var bStream = Observable.FromCoroutine(_ => B());
Observable.WhenAll(aStream, bStream)
.Subscribe(_ =>
{
Debug.Log("全部处理完");
});
}
Start
开启线程
void Start()
{
var threadAStream = Observable.Start(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(1));
return 10;
});
var threadBStream = Observable.Start(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(3));
return 10;
});
Observable.WhenAll(threadAStream, threadBStream)
.ObserveOnMainThread() //转到主线程
.Subscribe(results =>
{
Debug.LogFormat("{0}:{1}", results[0], results[1]);
});
}
UGUI 支持
public Button button;
public Toggle toggle;
public Image image;
public Slider slider;
public InputField inputField;
void Start()
{
button.OnClickAsObservable()
.Subscribe(_ =>
{
Debug.Log("button clicked");
});
toggle.OnValueChangedAsObservable()
.Subscribe(on =>
{
Debug.LogFormat("toggle value changed: {0}", on);
});
image.OnDragAsObservable()
.Subscribe(_ =>
{
Debug.Log("dragging");
});
slider.OnValueChangedAsObservable()
.Subscribe(value =>
{
Debug.Log("slider: " + value);
});
inputField.OnValueChangedAsObservable()
.Subscribe(value =>
{
Debug.Log("input: " + value);
});
inputField.OnEndEditAsObservable()
.Subscribe(value =>
{
Debug.Log("input: " + value);
});
}
查看源码,button.onClick 是 ButtonClickedEvent 类型,而 ButtonClickedEvent 继承自 UnityEvent, button.OnClickAsObservable 是对点击事件进行了封装,同理 UniRx 对其他组件的事件进行了封装
public static IObservable<Unit> OnClickAsObservable(this Button button)
{
return button.onClick.AsObservable();
}
public static IObservable<Unit> AsObservable(this UnityEngine.Events.UnityEvent unityEvent)
{
return Observable.FromEvent<UnityAction>(h => new UnityAction(h), h => unityEvent.AddListener(h), h => unityEvent.RemoveListener(h));
}
public static IObservable<Unit> FromEvent<TDelegate>(Func<Action, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
{
return new FromEventObservable<TDelegate>(conversion, addHandler, removeHandler);
}
绑定两个组件
public Toggle mToggle;
public Button mButton;
public Slider mSlider;
public Text mText;
void Start()
{
// 当 mToggle.isOn = true 时,mButton.interactable = true
mToggle.OnValueChangedAsObservable().SubscribeToInteractable(mButton);
// 滑动条变化时更新文本
mSlider.OnValueChangedAsObservable()
.SubscribeToText(mText, x => x.ToString());
}
Select
Select 是转换操作符,用于将一个事件源中的值转换成另一个类型的值
public Button buttonA;
public Button buttonB;
private void Start()
{
// Select将空参数Unit转换为string
buttonA.OnClickAsObservable()
.Select(_ => "A")
.Subscribe(btnId =>
{
Debug.LogFormat("button {0} clicked", btnId);
});
buttonB.OnClickAsObservable()
.Select(_ => "B")
.Subscribe(btnId =>
{
Debug.LogFormat("button {0} clicked", btnId);
});
}
public ReactiveCollection<int> IntList = new ReactiveCollection<int>();
void Start()
{
// Select 把每个值进行平方
IntList.ObserveAdd()
.Select(x => x.Value * x.Value)
.Subscribe(value =>
{
Debug.Log("add:" + value);
});
// 添加后触发事件
IntList.Add(10);
}
ReactiveProperty(响应式属性)
监听属性的变化,发送通知
// 0 是默认值,可序列化展示在面板上
public IntReactiveProperty Age = new IntReactiveProperty(0);
// 泛型写法,序列化很麻烦
public ReactiveProperty<string> Name = new ReactiveProperty<string>("Tom");
void Start()
{
Age.Subscribe(age =>
{
Debug.Log("inner received age changed");
});
// 赋值后触发事件
Age.Value = 10;
}
ReactiveCollection(响应式集合)
ReactiveCollection 类似于 List,监听集合的变化,发送通知
public ReactiveCollection<int> IntList = new ReactiveCollection<int>();
void Start()
{
IntList.ObserveAdd().Subscribe(value => Debug.Log("add:" + value));
IntList.ObserveRemove().Subscribe(value => Debug.Log("remove:" + value));
IntList.ObserveCountChanged().Subscribe(count => Debug.Log("count:" + count));
// 添加后触发事件
IntList.Add(10);
}
ReactiveDictionary(响应式字典)
ReactiveDictionary<string, string> mLanguageCode = new ReactiveDictionary<string, string>
{
{"cn","中文"},
{"en","英文"}
};
void Start()
{
mLanguageCode.ObserveAdd().Subscribe(addedLanguage => Debug.LogFormat("add:{0}", addedLanguage));
mLanguageCode.ObserveRemove().Subscribe(removedLanguage => Debug.LogFormat("remove:{0}", removedLanguage));
mLanguageCode.ObserveCountChanged().Subscribe(count => Debug.LogFormat("count:{0}", count));
mLanguageCode.Add("jp", "日文");
mLanguageCode.Remove("en");
}
MVP
View 依赖于 Presenter:View通过Presenter来获取数据并处理用户输入。
Presenter 依赖于 View 和 Model:负责处理View和Model之间的交互逻辑。
Model 不依赖于 View 或 Presenter:Model是独立的业务逻辑和数据层,它只负责数据的存储、处理和业务逻辑的实现。当Model的状态发生变化时,它可能会通过回调或事件通知Presenter。
// Presenter
public class EnemyExample : MonoBehaviour
{
// View
public Button attackBtn;
public Text HPText;
EnemyModel mEnemy = new EnemyModel(200);
void Start()
{
// UGUI组件和响应式属性绑定
attackBtn.OnClickAsObservable()
.Subscribe(_ =>
{
mEnemy.HP.Value -= 99;
});
mEnemy.HP.SubscribeToText(HPText);
mEnemy.IsDead
.Where(isDead => isDead)
.Select(isDead => !isDead)
.SubscribeToInteractable(attackBtn);
}
}
// Model
public class EnemyModel
{
public ReactiveProperty<long> HP;
public IReadOnlyReactiveProperty<bool> IsDead;
public EnemyModel(long initialHP)
{
HP = new ReactiveProperty<long>(initialHP);
IsDead = HP.Select(hp => hp <= 0).ToReactiveProperty();
}
}
ReactiveCommand
用法类似命令模式,ReactiveCommand 实现 IReactiveCommand<T> 接口
public interface IReactiveCommand<T> : IObservable<T>
{
IReadOnlyReactiveProperty<bool> CanExecute { get; } //内部使用,外部只读
bool Execute(T parameter); //外部调用的
}
当 CanExecute 为 true 时,调用 Execute,Command 才会执行,默认 CanExecute 为 true
void Start()
{
// 默认 CanExecute 为 true
var reactiveCommand = new ReactiveCommand();
reactiveCommand.Subscribe(_ =>
{
Debug.Log("每次Execute成功调用后执行");
});
reactiveCommand.Execute();
reactiveCommand.Execute();
}
泛型作为参数
void Start()
{
var reactiveCommand = new ReactiveCommand<int>();
reactiveCommand.Where(x => x % 2 == 0).Subscribe(x => Debug.LogFormat("{0}是偶数", x));
reactiveCommand.Where(x => x % 2 != 0).Timestamp().Subscribe(x => Debug.LogFormat("{0}是奇数,{1}", x.Value, x.Timestamp));
reactiveCommand.Execute(10);
reactiveCommand.Execute(11);
}
设置事件源
private void Start()
{
var mouseDownStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)).Select(_ => true);
var mouseUpStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonUp(0)).Select(_ => false);
var isMouseUp = Observable.Merge(mouseUpStream, mouseDownStream);
// 设置事件源和 CanExecute 为 false
var reactiveCommand = new ReactiveCommand(isMouseUp, false);
reactiveCommand.Subscribe(_ =>
{
Debug.Log("鼠标按下");
});
Observable.EveryUpdate().Subscribe(_ =>
{
reactiveCommand.Execute();
});
}
AsyncOperation(异步操作)
加载资源
void Start()
{
Resources.LoadAsync<GameObject>("资源名称").AsAsyncOperationObservable()
.Subscribe(resourceRequest =>
{
Instantiate(resourceRequest.asset);
});
}
加载场景
void Start()
{
// 加载进度
var progressObservable = new ScheduledNotifier<float>();
// 加载 Build Settings 中第 0 个场景
SceneManager.LoadSceneAsync(0).AsAsyncOperationObservable(progressObservable)
.Subscribe(_ =>
{
Debug.Log("load done");
});
progressObservable.Subscribe(progress =>
{
Debug.LogFormat("加载了:{0}%", progress * 100);
});
}
类 LINQ 操作符
Distinct
Distinct 意思是清晰的,不同的,用于查询不重复的结果集
List<string> list = new List<string>
{
"张三", "张三", "李四"
};
list.ToObservable()
.Distinct()
.Subscribe(name =>
{
Debug.Log(name);
});
Last
取列表最后一个元素,和 First 相反
class Student
{
public string Name;
public int Age;
}
void Start()
{
List<Student> students = new List<Student>
{
new Student{ Name = "张三", Age = 10 },
new Student{ Name = "张三", Age = 15 },
new Student{ Name = "李四", Age = 21 },
};
students.ToObservable()
.Last(student => student.Name == "张三")
.Subscribe(student =>
{
Debug.Log(student.Age);
});
}
SelectMany
将一个序列中的每个元素投影到另一个序列,并将这些序列合并为一个单一的序列。具体来说,它会对每个元素进行遍历处理,然后将结果序列合并起来
List<string> list = new List<string>
{
"123", "456"
};
list.ToObservable()
.SelectMany(c => c)
.Subscribe(c =>
{
Debug.Log(c);
});
输出
1
2
3
4
5
6
还可以实现协程的顺序执行
void Start()
{
var aStream = Observable.FromCoroutine(A);
var bStream = Observable.FromCoroutine(B);
aStream.SelectMany(bStream)
.Subscribe(_ => Debug.Log("A,B结束"));
}
IEnumerator A()
{
yield return new WaitForSeconds(1f);
Debug.Log("A");
}
IEnumerator B()
{
yield return new WaitForSeconds(1f);
Debug.Log("B");
}
Take
从指定位置开始,返回 N 项数据。
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Take(5) //前5次点击
.Subscribe(_ => Debug.Log("click"));
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Take(TimeSpan.FromSeconds(5)) //前5秒点击
.Subscribe(_ => Debug.Log("click2"));
只获取前 5 次点击
Concat
连接两个序列
var leftClickStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)).Take(3).Select(_ => "left");
var rightClickStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(1)).Take(3).Select(_ => "right");
leftClickStream.Concat(rightClickStream)
.Subscribe(s => Debug.Log(s));
OfType
根据指定类型筛选 IEnumerable 的元素
//Subject可以被视为一种事件源
var subjects = new Subject<object>();
subjects.OfType<object, string>()
.Subscribe(Debug.Log);
//OnNext方法可以向订阅者发送数据
subjects.OnNext(1);
subjects.OnNext(2);
subjects.OnNext("3");
subjects.OnNext(4);
//手动结束
subjects.OnCompleted();
筛选字符串类型数据并打印出来
GroupBy
分组
//Subject可以被视为一种事件源
var subjects = new Subject<int>();
subjects.GroupBy(number => number % 2 == 0 ? "偶数" : "奇数")
.Subscribe(group =>
{
group.Subscribe(num => Debug.Log(group.Key + " " + num));
});
//OnNext方法可以向订阅者发送数据
subjects.OnNext(1);
subjects.OnNext(2);
subjects.OnNext(3);
subjects.OnNext(4);
subjects.OnNext(5);
//手动结束
subjects.OnCompleted();
Range
生成指定范围内的整数序列
//从5开始,生成3个整数
Observable.Range(5, 3)
.Subscribe(num => Debug.Log(num));
Skip
跳过序列中指定数量的元素,返回剩余的元素
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Skip(2) //跳过前2次点击
.Subscribe(_ => Debug.Log("click"));
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Skip(TimeSpan.FromSeconds(5)) //跳过前5秒的点击
.Subscribe(_ => Debug.Log("click2"));
TakeWhile
如果指定的条件为 true,则返回序列中的元素,然后跳过剩余的元素。
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButton(0))
.TakeWhile(_ => !Input.GetMouseButtonUp(0))
.Subscribe(_ => Debug.Log("click"));
按住左键会持续log,知道左键抬起
SkipWhile
如果指定的条件为true,则跳过序列中的元素,然后返回剩余的元素。
Observable.EveryUpdate()
.SkipWhile(_ => !Input.GetMouseButton(0))
.Subscribe(_ => Debug.Log("click"));
鼠标点击后,持续输出
Zip
将指定函数应用于两个序列的对应元素,以生成结果序列。
var leftStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0));
var rightStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(1));
//l,r分别代表两个序列中的元素
leftStream.Zip(rightStream, (l, r) => Unit.Default)
.Subscribe(_ => Debug.Log("ok"));
左右键成对出现就会输出 ok
点击左键,右键,输出 ok
点击左,左,右,右,输出 ok ok
Repeat
在生成序列中重复该值的次数
Observable.Timer(TimeSpan.FromSeconds(1))
.Repeat()
.Subscribe(_ => Debug.Log("1 second"));
每隔 1 秒输出 1 次
Unity 独有操作符
TakeLast
获取序列的最后几项
Observable.Range(5, 5)
.TakeLast(3)
.Subscribe(num => Debug.Log(num));
TakeUntil
当第二个Observable发射了一项数据或者终止时,它会停止发射原始Observable的任何数据并终止
Observable.EveryUpdate()
.TakeUntil(Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)))
.Subscribe(_ => Debug.Log("123"));
鼠标点击之前会一直输出
SkipUntil
丢弃原始Observable发射的数据,直到第二个Observable发射了一项数据,与 TakeUnitl 相反
Observable.EveryUpdate()
.SkipUntil(Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)))
.Subscribe(_ => Debug.Log("按下"));
鼠标按下后会一直输出
BatchFrame
将多帧的数据合成一个批次
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.BatchFrame(100, FrameCountType.EndOfFrame)
.Subscribe(clicks => Debug.Log(clicks.Count));
输出 100 帧内的点击次数
Buffer
将Observable(可观察对象)发出的连续事件组合成一个列表,并在满足特定条件时将这些列表作为新的Observable发出
Observable.Interval(TimeSpan.FromSeconds(1))
.Buffer(3) //每3个事件组合成一个列表发出
.Subscribe(list => Debug.Log(list.Count));
Observable.Interval(TimeSpan.FromSeconds(1))
.Buffer(TimeSpan.FromSeconds(3)) //每3秒组合成一个列表发出
.Subscribe(list => Debug.Log(list.Count));
Delay
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Delay(TimeSpan.FromSeconds(1))
.Subscribe(_ => Debug.Log("点击1秒后"));
Throttle
节流阀,Throttle 操作符用于限制Observable(可观察对象)发出事件的频率。当事件以非常高的频率连续发出时,Throttle会忽略在一定时间窗口内的事件,只在时间窗口结束后发出最新的事件。
收到事件后,经过一个时间窗口没有收到新事件就触发
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Throttle(TimeSpan.FromSeconds(1))
.Subscribe(_ => Debug.Log("1秒后"));
点击鼠标后1秒内不在点击则输出,如果有点击则中重新计时1秒再输出
ThrottleFirst
每个时间窗口,只发送 Observable 的第一项数据
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.ThrottleFirst(TimeSpan.FromSeconds(5))
.Subscribe(_ => Debug.Log("点击"));
SampleFrame
每几帧采样一次
Observable.EveryUpdate()
.SampleFrame(5)
.Subscribe(_ => Debug.Log(Time.frameCount));
Sample
定期采样最近的数据,与 ThrottleFirst 类似
Observable.Interval(TimeSpan.FromSeconds(1.5))
.Sample(TimeSpan.FromSeconds(2))
.Subscribe(_ => Debug.Log(DateTime.Now.Second));
Timestamp
给 Observable 发送的数据附加一个时间戳
Observable.Interval(TimeSpan.FromSeconds(1))
.Timestamp()
.Subscribe(timestamp => Debug.Log(timestamp)); //timestamp是个结构体,包含原始数据和时间戳
Do
注册一个动作作为原始Observable 生命周期事件的一种占位符
Observable.ReturnUnit()
.Delay(TimeSpan.FromSeconds(1))
.Do(_ => Debug.Log("1秒后"))
.Delay(TimeSpan.FromSeconds(1))
.Do(_ => Debug.Log("2秒后"))
.Subscribe();
Materialize / Dematerialize
Materialize 将数据项和事件通知都当做数据项发射
一个合法的有限的 Obversable 将调用它的观察者的 onNext 方法零次或多次,然后调用观察者的 onCompleted 或 onError 正好一次。Materialize 操作符将这一系列调用,包括原来的onNext 通知和终止通知 onCompleted 或 onError 都转换为一个 Observable 发射的数据序列。
Dematerialize 操作符是 Materialize 的逆向过程,它将 Materialize 转换的结果还原成它原本的形式。Dematerialize 反转这个过程,将原始Observable 发射的 Notification 对象还原成 Observable 的通知。
var subject = new Subject<int>();
var onlyException = subject.Materialize()
.Where(notification => notification.Exception != null)
.Dematerialize();
subject.Subscribe(i => Debug.Log($"subscribe 1: {i}"), e => Debug.Log($"subscribe 1 exception {e.Message}"));
onlyException.Subscribe(i => Debug.Log($"subscribe 2: {i}"), e => Debug.Log($"subscribe 2 exception {e.Message}"));
subject.OnNext(123);
subject.OnError(new Exception("Test Exception"));
输出结果
subscribe 1: 123
subscribe 1 exception Test Exception
subscribe 2 exception Test Exception
Create
从头开始创建一个 Observable,给这个操作符传递一个接受观察者作为参数的函数,编写这个函数让它的行为表现为一个 Observable,恰当的调用观察者的 OnNext,OnError 和 OnCompleted 方法。
Observable.Create<int>(observer=>
{
observer.OnNext(1);
observer.OnNext(2);
observer.OnCompleted();
return Disposable.Create(() => Debug.Log("complete"));
}).Subscribe(n => Debug.Log(n));
Timeout
对原始Observable的一个镜像,如果过了一个指定的时长仍没有发射数据,它会发一个错误通知
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Timeout(TimeSpan.FromSeconds(5))
.Subscribe(_ => Debug.Log("点击"), e => Debug.Log(e.Message));
5 秒内没有点击报异常
Publish
将普通的 Observable 转换为可连接的 Observable,可连接的 Observable (connectable Observable) 与普通的 Observable 差不多,不过它并不会在被订阅时开始发射数据,而是直到使用了 Connect 操作符时才会开始。用这种方法,你可以在任何时候让一个 Observable 开始发射数据。
var unShared = Observable.Range(1, 2);
unShared.Subscribe(n => Debug.Log($"unShared #1: {n}"));
unShared.Subscribe(n => Debug.Log($"unShared #2: {n}"));
var shared = unShared.Publish();
shared.Subscribe(n => Debug.Log($"shared #1: {n}"));
shared.Subscribe(n => Debug.Log($"shared #2: {n}"));
Observable.Timer(TimeSpan.FromSeconds(2))
.Subscribe(_ => shared.Connect());
输出
unShared #1: 1
unShared #1: 2
unShared #2: 1
unShared #2: 2
shared #1: 1
shared #2: 1
shared #1: 2
shared #2: 2
Pairwise
Pairwise 将原始 Observable 序列中的每两个连续值打包成一个新的 Observable 序列的元素
Observable.Range(0, 5)
.Pairwise()
.Subscribe(pair => Debug.Log(pair.Current + ":" + pair.Previous));
输出
1:0
2:1
3:2
4:3
UniRx 独有操作符
NextFrame
跳过 1 帧
Debug.Log(Time.frameCount);
Observable.NextFrame()
.Subscribe(_ => Debug.Log(Time.frameCount));
输出
1
3
DelayFrame
跳过几帧
Debug.Log(Time.frameCount);
Observable.ReturnUnit()
.DelayFrame(10)
.Subscribe(_ => Debug.Log(Time.frameCount));
输出
1
12
ObserveOnMainThread
ObserveOnMainThread 可以确保你的 Observable 序列在任何线程上发出的通知都会被安全地转发到 Unity 的主线程
Debug.Log(Time.time);
Observable.Start(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(1));
return "thread result";
}).ObserveOnMainThread()
.Subscribe(res => Debug.Log(res + " " + Time.time));
输出
0
thread result 0.7934382
源码分析
IObserver 与 IObservable
Observable.Create<int>(observable =>
{
observable.OnNext(1);
observable.OnNext(2);
observable.OnCompleted();
return Disposable.Create(() => Debug.Log("complete"));
}).Subscribe(n => Debug.Log(n));
public static partial class Observable
{
public static IObservable<T> Create<T>(Func<IObserver<T>, IDisposable> subscribe)
{
if (subscribe == null) throw new ArgumentNullException("subscribe");
return new CreateObservable<T>(subscribe);
}
}
Create 是泛型方法,参数类型是 Func 委托,这个委托参数类型是 IObserver<T>,返回类型是 IDisposable,Create 的返回类型是 IObservable<T>
namespace System
{
public interface IObserver<in T>
{
void OnCompleted();
void OnError(Exception error);
void OnNext(T value);
}
}
IObserver<in T> 接口是观察者模式中的观察者。这里的 in 表示逆变量(contravariant),意味着泛型类型参数可以从一个类更改为它的某个派生类。
OnNext:当被观察者(Subject)有新的数据或状态信息时,会调用此方法将数据传递给观察者(Observer)。
OnError:当被观察者在发送数据过程中发生错误时,会调用此方法通知观察者。
OnCompleted:当被观察者完成数据发送后,会调用此方法通知观察者
namespace System
{
public interface IObservable<out T>
{
IDisposable Subscribe(IObserver<T> observer);
}
}
IObservable<out T> 接口是观察者模式中的可观察对象(也称为“主题”),它代表了一个可以产生数据或事件的对象。这个接口定义了一个 Subscribe 方法,该方法允许观察者(实现了 IObserver 接口的对象)注册自己,以便在可观察对象有新数据或事件产生时获得通知。Subscribe 方法的返回类型是 IDisposable 接口的对象,这样观察者可以在不再需要订阅时取消订阅。这里的 out 表示协变量(covariant)意味着泛型类型参数可以从一个类更改为它的某个基类。
internal class CreateObservable<T> : OperatorObservableBase<T>
{
readonly Func<IObserver<T>, IDisposable> subscribe;
public CreateObservable(Func<IObserver<T>, IDisposable> subscribe)
: base(true) // fail safe
{
this.subscribe = subscribe;
}
public CreateObservable(Func<IObserver<T>, IDisposable> subscribe, bool isRequiredSubscribeOnCurrentThread)
: base(isRequiredSubscribeOnCurrentThread)
{
this.subscribe = subscribe;
}
protected override IDisposable SubscribeCore(IObserver<T> observer, IDisposable cancel)
{
observer = new Create(observer, cancel);
return subscribe(observer) ?? Disposable.Empty;
}
class Create : OperatorObserverBase<T, T>
{
public Create(IObserver<T> observer, IDisposable cancel) : base(observer, cancel)
{
}
public override void OnNext(T value)
{
base.observer.OnNext(value);
}
public override void OnError(Exception error)
{
try { observer.OnError(error); }
finally { Dispose(); }
}
public override void OnCompleted()
{
try { observer.OnCompleted(); }
finally { Dispose(); }
}
}
}
CreateObservable 是一个具体的可观察对象,会把委托缓存起来,SubscribeCore 是 Subscribe 方法的核心逻辑,Create 是一个具体的观察者
public abstract class OperatorObservableBase<T> : IObservable<T>, IOptimizedObservable<T>
{
readonly bool isRequiredSubscribeOnCurrentThread;
public OperatorObservableBase(bool isRequiredSubscribeOnCurrentThread)
{
this.isRequiredSubscribeOnCurrentThread = isRequiredSubscribeOnCurrentThread;
}
public bool IsRequiredSubscribeOnCurrentThread()
{
return isRequiredSubscribeOnCurrentThread;
}
public IDisposable Subscribe(IObserver<T> observer)
{
var subscription = new SingleAssignmentDisposable();
if (isRequiredSubscribeOnCurrentThread && Scheduler.IsCurrentThreadSchedulerScheduleRequired)
{
Scheduler.CurrentThread.Schedule(() => subscription.Disposable = SubscribeCore(observer, subscription));
}
else
{
subscription.Disposable = SubscribeCore(observer, subscription);
}
return subscription;
}
protected abstract IDisposable SubscribeCore(IObserver<T> observer, IDisposable cancel);
}
OperatorObservableBase 是可观察对象的抽象基类,调用 Subscribe 方法会调用子类的 SubscribeCore 方法,传入观察者
public abstract class OperatorObserverBase<TSource, TResult> : IDisposable, IObserver<TSource>
{
protected internal volatile IObserver<TResult> observer;
IDisposable cancel;
public OperatorObserverBase(IObserver<TResult> observer, IDisposable cancel)
{
this.observer = observer;
this.cancel = cancel;
}
public abstract void OnNext(TSource value);
public abstract void OnError(Exception error);
public abstract void OnCompleted();
public void Dispose()
{
observer = UniRx.InternalUtil.EmptyObserver<TResult>.Instance;
var target = System.Threading.Interlocked.Exchange(ref cancel, null);
if (target != null)
{
target.Dispose();
}
}
}
OperatorObserverBase 是观察者的抽象基类,定义一些核心方法
总结: UniRx 的数据(事件)是从 IObservable 推送过来,然后在 IObserver 进行捕获。
Range 操作符源码
Observable.Range(0, 5)
.Subscribe(num => Debug.Log(num));
public static IObservable<int> Range(int start, int count)
{
return Range(start, count, Scheduler.DefaultSchedulers.Iteration);
}
public static IObservable<int> Range(int start, int count, IScheduler scheduler)
{
return new RangeObservable(start, count, scheduler);
}
Observable.Range 会创建一个 RangeObservable 对象,Scheduler 用于控制 Observable 的操作在哪个线程上执行
internal class RangeObservable : OperatorObservableBase<int>
{
readonly int start;
readonly int count;
readonly IScheduler scheduler;
public RangeObservable(int start, int count, IScheduler scheduler)
: base(scheduler == Scheduler.CurrentThread)
{
if (count < 0) throw new ArgumentOutOfRangeException("count < 0");
this.start = start;
this.count = count;
this.scheduler = scheduler;
}
protected override IDisposable SubscribeCore(IObserver<int> observer, IDisposable cancel)
{
observer = new Range(observer, cancel);
if (scheduler == Scheduler.Immediate)
{
for (int i = 0; i < count; i++)
{
int v = start + i;
observer.OnNext(v);
}
observer.OnCompleted();
return Disposable.Empty;
}
else
{
var i = 0;
return scheduler.Schedule((Action self) =>
{
if (i < count)
{
int v = start + i;
observer.OnNext(v);
i++;
self();
}
else
{
observer.OnCompleted();
}
});
}
}
class Range : OperatorObserverBase<int, int>
{
public Range(IObserver<int> observer, IDisposable cancel)
: base(observer, cancel)
{
}
public override void OnNext(int value)
{
try
{
base.observer.OnNext(value);
}
catch
{
Dispose();
throw;
}
}
public override void OnError(Exception error)
{
try { observer.OnError(error); }
finally { Dispose(); }
}
public override void OnCompleted()
{
try { observer.OnCompleted(); }
finally { Dispose(); }
}
}
}
RangeObservable 是一个具体的可观察者,缓存起始下标和数量,Range 是一个具体的观察者
大致的结构图
Scheduler
Scheduler 是一个任务调度器
public static partial class Scheduler
{
// configurable defaults
public static class DefaultSchedulers
{
static IScheduler iteration;
public static IScheduler Iteration
{
get
{
return iteration ?? (iteration = Scheduler.CurrentThread);
}
set
{
iteration = value;
}
}
}
//不同的调度器
public static readonly IScheduler Immediate = new ImmediateScheduler();
public static readonly IScheduler ThreadPool = new ThreadPoolScheduler();
public static readonly IScheduler CurrentThread = new CurrentThreadScheduler();
}
Scheduler.MainThread 这个调度器在主线程上执行任务
Scheduler.Immediate 这个调度器会立即在当前线程上执行工作,没有延迟
Scheduler.ThreadPool 这个调度器使用线程池中的线程来执行工作
Scheduler.CurrentThread 这个调度器是在当前线程上执行工作,可以有延迟
Range 中用到的 Scheduler.DefaultSchedulers.Iteration 就是 Scheduler.CurrentThread 调度器
public interface IScheduler
{
DateTimeOffset Now { get; }
IDisposable Schedule(Action action);
IDisposable Schedule(TimeSpan dueTime, Action action);
}
public static partial class Scheduler
{
class CurrentThreadScheduler : IScheduler
{
[ThreadStatic]
static SchedulerQueue s_threadLocalQueue;
[ThreadStatic]
static Stopwatch s_clock;
private static SchedulerQueue GetQueue()
{
return s_threadLocalQueue;
}
private static void SetQueue(SchedulerQueue newQueue)
{
s_threadLocalQueue = newQueue;
}
private static TimeSpan Time
{
get
{
if (s_clock == null)
s_clock = Stopwatch.StartNew();
return s_clock.Elapsed;
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static bool IsScheduleRequired
{
get
{
return GetQueue() == null;
}
}
public IDisposable Schedule(Action action)
{
return Schedule(TimeSpan.Zero, action);
}
public IDisposable Schedule(TimeSpan dueTime, Action action)
{
if (action == null)
throw new ArgumentNullException("action");
var dt = Time + Scheduler.Normalize(dueTime);
var si = new ScheduledItem(action, dt);
var queue = GetQueue();
if (queue == null)
{
queue = new SchedulerQueue(4);
queue.Enqueue(si);
CurrentThreadScheduler.SetQueue(queue);
try
{
Trampoline.Run(queue);
}
finally
{
CurrentThreadScheduler.SetQueue(null);
}
}
else
{
queue.Enqueue(si);
}
return si.Cancellation;
}
static class Trampoline
{
public static void Run(SchedulerQueue queue)
{
while (queue.Count > 0)
{
var item = queue.Dequeue();
if (!item.IsCanceled)
{
var wait = item.DueTime - CurrentThreadScheduler.Time;
if (wait.Ticks > 0)
{
Thread.Sleep(wait);
}
if (!item.IsCanceled)
item.Invoke();
}
}
}
}
}
}
调度器的核心方法是 Schedule,CurrentThreadScheduler 会把 TimeSpan 和 Action 封装到 ScheduledItem 中,然后添加到队列中,Trampoline.Run 会依次执行 Action,当时间大于0时,调用 Thread.Sleep 等待,否则立即执行
Select 操作符源码
Observable.Range(0, 5)
.Select(num =>
{
Debug.Log("orignal number " + num);
return (num * 2).ToString();
})
.Subscribe(num => Debug.Log(num));
public static partial class Observable
{
public static IObservable<TR> Select<T, TR>(this IObservable<T> source, Func<T, TR> selector)
{
return new SelectObservable<T, TR>(source, selector);
}
}
Select 是一个扩展方法,source 是原始的可观察对象,即 Observable.Range 生成的可观察对象,selector 是一个转换器,T 是原始数据类型,TR 是转换后的数据类型,这个例子中 T 是 int,TR 是 string。
internal class SelectObservable<T, TR> : OperatorObservableBase<TR>, ISelect<TR>
{
readonly IObservable<T> source;
readonly Func<T, TR> selector;
public SelectObservable(IObservable<T> source, Func<T, TR> selector)
: base(source.IsRequiredSubscribeOnCurrentThread())
{
this.source = source;
this.selector = selector;
}
protected override IDisposable SubscribeCore(IObserver<TR> observer, IDisposable cancel)
{
if (selector != null)
{
return source.Subscribe(new Select(this, observer, cancel));
}
else
{
return source.Subscribe(new Select_(this, observer, cancel));
}
}
class Select : OperatorObserverBase<T, TR>
{
readonly SelectObservable<T, TR> parent;
public Select(SelectObservable<T, TR> parent, IObserver<TR> observer, IDisposable cancel)
: base(observer, cancel)
{
this.parent = parent;
}
public override void OnNext(T value)
{
var v = default(TR);
try
{
v = parent.selector(value);
}
catch (Exception ex)
{
try { observer.OnError(ex); } finally { Dispose(); }
return;
}
observer.OnNext(v);
}
public override void OnError(Exception error)
{
try { observer.OnError(error); } finally { Dispose(); }
}
public override void OnCompleted()
{
try { observer.OnCompleted(); } finally { Dispose(); }
}
}
}
SelectObservable 是一个具体的可观察对象,缓存了原始可观察对象和转换器,Select 是一个具体的观察者,在调用 Next 方法前,先使用 selector 转换成目标类型的数据
Where 操作符源码
Observable.Range(0, 5)
.Where(num => num > 2)
.Subscribe(num => Debug.Log(num));
public static partial class Observable
{
public static IObservable<T> Where<T>(this IObservable<T> source, Func<T, bool> predicate)
{
return new WhereObservable<T>(source, predicate);
}
}
这里 predicate 是判断条件,即例子中 num > 2,返回类型 bool 表示条件是否满足
internal class WhereObservable<T> : OperatorObservableBase<T>
{
readonly IObservable<T> source;
readonly Func<T, bool> predicate;
public WhereObservable(IObservable<T> source, Func<T, bool> predicate)
: base(source.IsRequiredSubscribeOnCurrentThread())
{
this.source = source;
this.predicate = predicate;
}
protected override IDisposable SubscribeCore(IObserver<T> observer, IDisposable cancel)
{
if (predicate != null)
{
return source.Subscribe(new Where(this, observer, cancel));
}
else
{
return source.Subscribe(new Where_(this, observer, cancel));
}
}
class Where : OperatorObserverBase<T, T>
{
readonly WhereObservable<T> parent;
public Where(WhereObservable<T> parent, IObserver<T> observer, IDisposable cancel)
: base(observer, cancel)
{
this.parent = parent;
}
public override void OnNext(T value)
{
var isPassed = false;
try
{
isPassed = parent.predicate(value);
}
catch (Exception ex)
{
try { observer.OnError(ex); } finally { Dispose(); }
return;
}
if (isPassed)
{
observer.OnNext(value);
}
}
public override void OnError(Exception error)
{
try { observer.OnError(error); } finally { Dispose(); }
}
public override void OnCompleted()
{
try { observer.OnCompleted(); } finally { Dispose(); }
}
}
}
WhereObservable 是具体的可观察对象,Where 是具体的观察者,predicate 条件满足的才能调用 OnNext 方法
Delay 操作符源码
Debug.Log(Time.time);
Observable.Range(0, 2)
.Delay(TimeSpan.FromSeconds(1f))
.Subscribe(num => Debug.Log(num + " " + Time.time));
public static partial class Observable
{
public static IObservable<T> Delay<T>(this IObservable<T> source, TimeSpan dueTime)
{
return source.Delay(dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations);
}
public static IObservable<TSource> Delay<TSource>(this IObservable<TSource> source, TimeSpan dueTime, IScheduler scheduler)
{
return new DelayObservable<TSource>(source, dueTime, scheduler);
}
}
public static partial class Scheduler
{
public static class DefaultSchedulers
{
static IScheduler timeBasedOperations;
public static IScheduler TimeBasedOperations
{
get
{
#if UniRxLibrary
return timeBasedOperations ?? (timeBasedOperations = Scheduler.ThreadPool);
#else
// MainThread as default for TimeBased Operation
return timeBasedOperations ?? (timeBasedOperations = Scheduler.MainThread);
#endif
}
set
{
timeBasedOperations = value;
}
}
}
}
这里用到 Scheduler.MainThread 这个调度器,在主线程上执行任务
class MainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing
{
readonly Action<object> scheduleAction;
public MainThreadScheduler()
{
MainThreadDispatcher.Initialize();
scheduleAction = new Action<object>(Schedule);
}
IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation)
{
// zero == every frame
if (dueTime == TimeSpan.Zero)
{
yield return null; // not immediately, run next frame
}
else
{
yield return new WaitForSeconds((float)dueTime.TotalSeconds);
}
if (cancellation.IsDisposed) yield break;
MainThreadDispatcher.UnsafeSend(action);
}
public IDisposable Schedule(TimeSpan dueTime, Action action)
{
var d = new BooleanDisposable();
var time = Scheduler.Normalize(dueTime);
MainThreadDispatcher.SendStartCoroutine(DelayAction(time, action, d));
return d;
}
}
MainThreadScheduler 使用协程来实现延时操作,MainThreadDispatcher 是一个 mono 脚本,借助它使用协程的功能
internal class DelayObservable<T> : OperatorObservableBase<T>
{
readonly IObservable<T> source;
readonly TimeSpan dueTime;
readonly IScheduler scheduler;
public DelayObservable(IObservable<T> source, TimeSpan dueTime, IScheduler scheduler)
: base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread())
{
this.source = source;
this.dueTime = dueTime;
this.scheduler = scheduler;
}
protected override IDisposable SubscribeCore(IObserver<T> observer, IDisposable cancel)
{
return new Delay(this, observer, cancel).Run();
}
class Delay : OperatorObserverBase<T, T>
{
readonly DelayObservable<T> parent;
readonly object gate = new object();
bool hasFailed;
bool running;
bool active;
Exception exception;
Queue<Timestamped<T>> queue;
bool onCompleted;
DateTimeOffset completeAt;
IDisposable sourceSubscription;
TimeSpan delay;
bool ready;
SerialDisposable cancelable;
public Delay(DelayObservable<T> parent, IObserver<T> observer, IDisposable cancel) : base(observer, cancel)
{
this.parent = parent;
}
public IDisposable Run()
{
cancelable = new SerialDisposable();
active = false;
running = false;
queue = new Queue<Timestamped<T>>();
onCompleted = false;
completeAt = default(DateTimeOffset);
hasFailed = false;
exception = default(Exception);
ready = true;
delay = Scheduler.Normalize(parent.dueTime);
var _sourceSubscription = new SingleAssignmentDisposable();
sourceSubscription = _sourceSubscription; // assign to field
_sourceSubscription.Disposable = parent.source.Subscribe(this);
return StableCompositeDisposable.Create(sourceSubscription, cancelable);
}
public override void OnNext(T value)
{
var next = parent.scheduler.Now.Add(delay);
var shouldRun = false;
lock (gate)
{
queue.Enqueue(new Timestamped<T>(value, next));
shouldRun = ready && !active;
active = true;
}
if (shouldRun)
{
cancelable.Disposable = parent.scheduler.Schedule(delay, DrainQueue);
}
}
public override void OnError(Exception error)
{
// 。。。
}
public override void OnCompleted()
{
// 。。。
}
void DrainQueue(Action<TimeSpan> recurse)
{
// 。。。
}
}
}
DelayObservable 是一个具体的可观察对象,缓存延迟时间和调度器 scheduler,Delay 是一个具体的观察者,OnNext 中执行的 parent.scheduler.Schedule 方法就是前面 MainThreadScheduler.Schedule 方法。
StableCompositeDisposable 这个类把多个 IDisposable 对象封装到一起,当调用 StableCompositeDisposable.Dispose(),会依次调用内部对象的 Dispose 方法
Subject 源码
var subject = new Subject<int>();
subject.Subscribe(i => Debug.Log(i), () => Debug.Log("complete1"));
subject.Subscribe(i => Debug.Log(i * 2), () => Debug.Log("complete2"));
subject.Subscribe(i => Debug.Log(i * 3), () => Debug.Log("complete3"));
subject.OnNext(1);
subject.OnCompleted();
输出
1
2
3
complete1
complete2
complete3
public interface ISubject<TSource, TResult> : IObserver<TSource>, IObservable<TResult>
{
}
public interface ISubject<T> : ISubject<T, T>, IObserver<T>, IObservable<T>
{
}
public sealed class Subject<T> : ISubject<T>, IDisposable, IOptimizedObservable<T>
{
object observerLock = new object();
bool isStopped;
bool isDisposed;
Exception lastError;
IObserver<T> outObserver = EmptyObserver<T>.Instance;
public void OnCompleted()
{
IObserver<T> old;
lock (observerLock)
{
if (isStopped) return;
old = outObserver;
outObserver = EmptyObserver<T>.Instance;
isStopped = true;
}
old.OnCompleted();
}
public void OnError(Exception error)
{
if (error == null) throw new ArgumentNullException("error");
IObserver<T> old;
lock (observerLock)
{
if (isStopped) return;
old = outObserver;
outObserver = EmptyObserver<T>.Instance;
isStopped = true;
lastError = error;
}
old.OnError(error);
}
public void OnNext(T value)
{
outObserver.OnNext(value);
}
public IDisposable Subscribe(IObserver<T> observer)
{
if (observer == null) throw new ArgumentNullException("observer");
var ex = default(Exception);
lock (observerLock)
{
if (!isStopped)
{
var listObserver = outObserver as ListObserver<T>;
if (listObserver != null)
{
//注册第三个及以后
outObserver = listObserver.Add(observer);
}
else
{
var current = outObserver;
if (current is EmptyObserver<T>)
{
//注册第一个
outObserver = observer;
}
else
{
//注册第二个
outObserver = new ListObserver<T>(new ImmutableList<IObserver<T>>(new[] { current, observer }));
}
}
return new Subscription(this, observer);
}
ex = lastError;
}
if (ex != null)
{
observer.OnError(ex);
}
else
{
observer.OnCompleted();
}
return Disposable.Empty;
}
class Subscription : IDisposable
{
readonly object gate = new object();
Subject<T> parent;
IObserver<T> unsubscribeTarget;
public Subscription(Subject<T> parent, IObserver<T> unsubscribeTarget)
{
this.parent = parent;
this.unsubscribeTarget = unsubscribeTarget;
}
public void Dispose()
{
// 。。。
}
}
}
Subject 继承 ISubject,而 ISubject 又继承 IObserver 和 IObservable,所以 Subject 既是观察者,又是可观察对象。 Subject 内部的 outObserver 表示所有注册的观察者,当观察者变多后,会一个创建 ListObserver,ListObserver 内部有个数组,把所有观察者都添加到数组中,当调用 OnNext 时,会一直执行数组中每个观察者的 OnNext
ReactiveProperty 源码
public ReactiveProperty<string> Name = new ReactiveProperty<string>("Tom");
void Start()
{
Name.Subscribe(str =>Debug.Log(str));
Name.Value = "Jerry";
}
输出
Tom
Jerry
public interface IReadOnlyReactiveProperty<T> : IObservable<T>
{
T Value { get; }
bool HasValue { get; }
}
public interface IReactiveProperty<T> : IReadOnlyReactiveProperty<T>
{
new T Value { get; set; }
}
public class ReactiveProperty<T> : IReactiveProperty<T>, IDisposable, IOptimizedObservable<T>, IObserverLinkedList<T>
{
//比较器
#if !UniRxLibrary
static readonly IEqualityComparer<T> defaultEqualityComparer = UnityEqualityComparer.GetDefault<T>();
#else
static readonly IEqualityComparer<T> defaultEqualityComparer = EqualityComparer<T>.Default;
#endif
#if !UniRxLibrary
[SerializeField]
#endif
T value = default(T);
//链表根节点
[NonSerialized]
ObserverNode<T> root;
[NonSerialized]
ObserverNode<T> last;
[NonSerialized]
bool isDisposed = false;
protected virtual IEqualityComparer<T> EqualityComparer => defaultEqualityComparer;
public T Value
{
get
{
return value;
}
set
{
if (!EqualityComparer.Equals(this.value, value))
{
SetValue(value);
if (isDisposed)
return;
RaiseOnNext(ref value);
}
}
}
public ReactiveProperty(): this(default(T)){}
public ReactiveProperty(T initialValue)
{
SetValue(initialValue);
}
void RaiseOnNext(ref T value)
{
var node = root;
while (node != null)
{
node.OnNext(value);
node = node.Next;
}
}
protected virtual void SetValue(T value)
{
this.value = value;
}
public IDisposable Subscribe(IObserver<T> observer)
{
if (isDisposed)
{
observer.OnCompleted();
return Disposable.Empty;
}
// raise latest value on subscribe
observer.OnNext(value);
// subscribe node, node as subscription.
var next = new ObserverNode<T>(this, observer);
if (root == null)
{
root = last = next;
}
else
{
last.Next = next;
next.Previous = last;
last = next;
}
return next;
}
}
ReactiveProperty 最终继承 IObservable,所以它是一个可观察对象,当调用 Subscribe 时,它会先触发一次 observer.OnNext,所以例子中先输出了 Tom,当多次调用 Subscribe 时,会在内部形成一个链表,把 observer 封装到 ObserverNode 中,这些节点再形成一条链表,当使用 Value 设置新值时,RaiseOnNext 方法中会一次调用每个节点的 OnNext 方法
未完待续