UniRx 入门

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 方法

未完待续

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里给您举一个使用RxJava框架的实例: 假设有一个需求,要求从一个API接口中获取用户信息并显示在界面上。我们可以使用RxJava来实现这个需求: 首先,在对应的Activity或Fragment中,我们定义一个Observable对象,用来发出网络请求并获取用户信息: ```java Observable<User> userObservable = Api.getUserInfo(userId); ``` 然后,我们可以使用subscribeOn()方法指定请求在IO线程中执行,使用observeOn()方法指定结果在主线程中回调: ```java userObservable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<User>() { @Override public void onSubscribe(Disposable d) { // 可以在这里做一些初始化操作,比如显示loading等 } @Override public void onNext(User user) { // 获取到用户信息后,更新UI显示 updateUi(user); } @Override public void onError(Throwable e) { // 出现异常时,可以做一些错误处理,比如弹出Toast提示等 showError(e.getMessage()); } @Override public void onComplete() { // 请求完成后,可以在这里做一些清理工作,比如隐藏loading等 } }); ``` 在上面的代码中,我们通过实现Observer接口来处理请求结果。在onNext()方法中,我们可以拿到获取到的用户信息,然后更新UI显示。在onError()方法中,我们可以处理请求出现异常的情况,比如弹出Toast提示。在onComplete()方法中,我们可以做一些清理工作,比如隐藏loading。 这就是一个简单的使用RxJava来获取用户信息的示例。通过使用RxJava,我们可以简化异步编程的复杂度,使代码更加清晰易读。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值