文章目录
第二章 UniRx的动作原理
2.1 Observable 是什么
2.1.1 事件驱动程序
当应用程序在执行中发生了事件,通过发送事件消息来通知。这个事件消息在别的地方被订阅,执行接收到消息后的处理。
2.1.2 Observer Pattern(观察者模式)
UniRx是在观察者模式到基础上制作的。
-
观察者模式概要
- Observer Object:事件消息观察者。事件消息的接收方。接收事件消息,并对其进行处理。
- Subject Object:事件消息的发行方。可以登陆多个观察对象,当事件发行时通知所有观察者。
-
观察者接口 interface IObserver
using System; namespace System { public interface IObserver<in T> { // 事件发行,正常接收事件消息 void OnNext(T value); // 发行中,异常发生时 void OnError(Exception error); // 事件消息发行完,正常结束后 void OnCompleted(); } }
-
接收观察对象的 interface IObservable
IObservable 是接收 IObserver的接口
namespace System { public interface IObservable<out T> { //IObserver<T> 作为参数 返回IDisposable借口 IDisposable Subscribe(IObserver<T> observer); } }
继承IObservable的对象,通过Subscribe(),对观察者进行登陆。
并通过返回值的IDisposable的Dispose()方法对登陆的观察者进行解除。
Subject继承IObservable的
-
Observer对象进行管理的【Subject】
UniRx提供了Subject Class;
-
用途
-
特征
继承了IObserver和IObservable
可以同时对事件消息进行输入和输出
可以登陆多个IObserver
ISubject
using System; namespace UniRx { public interface ISubject<TSource,TResult> : IObserver<TSource>,IObservable<TResult> { } public interface ISubject<T> : ISubject<T,T>,IObserver<T>,IObservable<T> { } }
-
-
Subject的利用例
using System; namespace Sample.Section2.MyObservers { //继承IObserver<T> 用来打印消息的Observer public class PrintLogObserver<T> : IObserver<T> { public void OnCompleted() { UnityEngine.Debug.Log("OnCompleted"); } public void OnError(Exception error) { UnityEngine.Debug.LogError(error); } public void OnNext(T value) { UnityEngine.Debug.Log(value); } } }
using System; using System.Collections; using UniRx; using UnityEngine; namespace Sample.Section2.MyObservers { //指定倒计时 事件通知 public class CountDownEventProvider : MonoBehaviour { [SerializeField] private int _countSeconds = 10; //Subject private Subject<int> _subject; //只公开 Subject 的IObservable的接口 public IObservable<int> CountDownObservable => _subject; private void Awake() { //Subject 生成 _subject = new Subject<int>(); //开启 倒计时协程 StartCoroutine(CountCoroutine()); } private IEnumerator CountCoroutine() { var current = _countSeconds; while (current > 0) { //发行现在的值 _subject.OnNext(current); current--; yield return new WaitForSeconds(1f); } //最后发行 0 和 OnComplete _subject.OnNext(0); _subject.OnCompleted(); } private void OnDestroy() { //当GameObject销毁是 释放Subject _subject.Dispose(); } } }
using System; using UnityEngine; namespace Sample.Section2.MyObservers { public class ObserveEventComponent : MonoBehaviour { [SerializeField] private CountDownEventProvider _countDownEventProvider; //Observer private PrintLogObserver<int> _printLogObserver; private IDisposable _disposable; private void Start() { //PrintLogObserver _printLogObserver = new PrintLogObserver<int>(); //调用 Subject 的 Subscribe ,登陆 observer _disposable = _countDownEventProvider .CountDownObservable .Subscribe(_printLogObserver); } private void OnDestroy() { //GameObject 销毁时 注销事件 _disposable?.Dispose(); } } }
-
实现下简单的Subject
using System; using UniRx; using System.Collections.Generic; namespace Sample.Section2.MySubjects { //简单的MySubject public class MySubject<T> : ISubject<T>,IDisposable { public bool IsStopped { get; } = false; public bool IsDisposed { get; } = false; private readonly object _lockObject = new object(); //途中发生的异常 private Exception _error; //登陆的 Observer List private List<IObserver<T>> _observers; public MySubject() { _observers = new List<IObserver<T>>(); } //实现 IObserver.OnNext public void OnNext(T value) { if (IsStopped) return; lock (_lockObject) { ThrowIfDisposed(); //把消息传给所有的observer foreach (var observer in _observers) { observer.OnNext(value); } } } //实现Observer.OnError public void OnError(Exception error) { lock (_lockObject) { ThrowIfDisposed(); if (IsStopped) return; this._error = error; try { foreach (var observer in _observers) { observer.OnError(_error); } } finally { Dispose(); } } } //实现Observer.OnCompleted public void OnCompleted() { lock (_lockObject) { ThrowIfDisposed(); if (IsStopped) return; try { foreach (var observer in _observers) { observer.OnCompleted(); } } finally { Dispose(); } } } //实现IObservable.Subscribe public IDisposable Subscribe(IObserver<T> observer) { lock (_lockObject) { //如果已经结束 发行OnError 或者OnCompleted if (IsStopped) { if (_error != null) { observer.OnError(_error); } else { observer.OnCompleted(); } return Disposable.Empty; } _observers.Add(observer);//添加到List里 return new Subscription(this, observer); } } private void ThrowIfDisposed() { if (IsDisposed) throw new ObjectDisposedException("MySubject"); } public void Dispose() { lock (_lockObject) { if (!IsDisposed) { _observers.Clear(); _observers = null; _error = null; } } } // private sealed class Subscription : IDisposable { private readonly IObserver<T> _observer; private readonly MySubject<T> _parent; public Subscription(MySubject<T> parent, IObserver<T> observer) { this._parent = parent; this._observer = observer; } public void Dispose() { // Dispose 的时候从 List里删除 _parent._observers.Remove(_observer); } } } }
-
更简单的Subscribe()
使用语法糖可以更简单优雅的处理事件消息
using System; using UnityEngine; using UniRx; namespace Sample.Section2.MyObservers { public class ObserveEventComponent2 : MonoBehaviour { [SerializeField] private CountDownEventProvider _countDownEventProvider; private PrintLogObserver<int> _printLogObserver; private IDisposable _disposable; private void Start() { _disposable = _countDownEventProvider .CountDownObservable .Subscribe( x => Debug.Log(x), // OnNext ex => Debug.LogError(ex), // OnError () => Debug.Log("OnCompleted!")); // OnCompleted } private void OnDestroy() { _disposable?.Dispose(); } } }
2.1.3 从观察者模式考虑Observable
-
Operator
输出IObservable
输入IObserver 对输入的消息进行加工
使用咧
using System; using UniRx; using UnityEngine; namespace Sample.Section2.Operators { //对消息进行过滤 public class OperatorTest : MonoBehaviour { private void Start() { var subject = new Subject<int>(); //直接订阅 subject.Subscribe(x => Debug.Log("raw: " + x)); //过滤 0以下的数 subject .Where(x => x > 0) .Subscribe(x => Debug.Log("filter: " + x)); // 发行消息 subject.OnNext(1); subject.OnNext(-1); subject.OnNext(3); subject.OnNext(0); // 结束 subject.OnCompleted(); subject.Dispose(); } } }
-
Operator和Subject的不同
- 两个都有IObserver和IObservable, 都可以对消息进行输入和输出
- Subject 内部有一个List<IObserver> 可以储存多个IObserver
- Operator没有,
-
Scheduler
- 消息处理的时机和线程进行处理
- Observable.Time / Observable.Interval
- Delay / Timeout.
- 消息处理的时机和线程进行处理
2.1.4 Observable
- 简单来说 处理消息的流程 消息流 就称为Observable