Avalonia ReactiveUI 系列一 初识反应式编程
前言
学习本内容的前提:- 了解MVVM
- 了解XAML语法
- 了解C#基础
- 了解Avalonia
说到ReactiveUI,必须先了解什么是Reactive。Reactive编程:一种围绕异步数据流构建的开发模型,是一种响应式编程的体现。
响应式编程(Reactive Programming)这个概念上,它是一种基于事件模式的模型。在异步编程模式中一般来说有两种获取结果的方式,一个就是主动轮训,我们把它称为 Proactive 方式。另一个就是被动接收反馈,我们称为 Reactive。简单来说,在 Reactive 方式中,上一个任务的结果的反馈就是一个事件,这个事件的到来将会触发下一个任务的执行。这也就是 Reactive 的内涵。我们把处理和发出事件的主体称为 Reactor,它可以接受事件并处理,也可以在处理完事件后,发出下一个事件给其他 Reactor。两个 Reactors 之间没有必然的强耦合,他们之间通过消息管道来传递消息。Reactor 可以定义一些事件处理函数,根据接收到的事件不同类型来进行不同的处理。
需要强调的是,实现 Reactive 模型最核心的是线程和消息管道。线程用于侦听事件,消息管道用于 Reactor 之间通信不同的消息。与他们相关的是事件管理器用于注册、注销事件,而消息分配器则会根据消息类型分发。
响应式编程的思路大概如下:你可以用包括 Click 和 Hover 事件在内的任何东西创建 Data stream。Stream 廉价且常见,任何东西都可以是一个 Stream:变量、用户输入、属性、Cache、数据结构等等。举个例子,想像一下你的 Twitter feed 就像是 Click events 那样的 Data stream,你可以监听它并相应的作出响应。
在这个基础上,你还有令人惊艳的函数去组合、创建、过滤这些 Streams,这就是函数式魔法的用武之地。Stream 能接受一个,甚至多个 Stream 为输入,你可以融合两个 Stream,也可以从一个 Stream 中过滤出你感兴趣的 Events 以生成一个新的 Stream,还可以把一个 Stream 中的数据值 映射到一个新的 Stream 中。
Rx主要是做三件事:数据/事件的创建、组合/转换数据流、监听处理结果
Rx的组成包括5部分,被观察者或者叫发射源,观察者/订阅者或者叫接收源,订阅,调度器,操作符。
- Observable 被观察者可以被观察者订阅,被观察者将数据push给所有的订阅者
- Subscriber /Observer
- Subscription 订阅可以被取消订阅
- Schedulers
调度器是Rx的线程池,操作中执行的任务可以指定线程池,我们可以通过subscribeOn来指定Observable的任务在某线程池中执行Observable也可以通过observeOn来指定订阅者/观察者们,在哪个线程执行onNext, onComplete, onError - Operators 操作符可以对数据流进行各种操作,包括创建,转换,过滤,组装,合并 ,筛选等等
其中最主要的是 Observable、Operators、Sechedulers
微软给的定义是,Rx是一个函数库,让开发者可以利用可观察序列和LINQ风格查询操作符来编写异步和基于事件的程序,使用Rx,开发者可以用Observables表示异步数据流,用LINQ操作符查询异步数据流, 用Schedulers参数化异步数据流的并发处理,Rx可以这样定义:Rx = Observables + LINQ + Schedulers。
一、MVVM
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。
public interface IObserver<in T>
{
void OnNext(T value);
void OnError(Exception error);
void OnCompleted();
}
使用观察者模式可以很方便的做下面的操作:
- 创建:Rx可以方便的创建事件流和数据流
- 组合:Rx使用查询式的操作符组合和变换数据流
- 监听:Rx可以订阅任何可观察的数据流并执行操作
Rx对于对于并发性或异步性没有任何特殊的偏好,Observable可以用任何方式实现,线程池、事件循环、非阻塞IO、Actor模式,任何满足你的需求的,你擅长或偏好的方式都可以。无论你选择怎样实现它,无论底层实现是阻塞的还是非阻塞的,客户端代码将所有与Observable的交互都当做是异步的。
Observable类型给GOF的观察者模式添加了两种缺少的语义,这样就和Iterable类型中可用的操作一致了:
生产者可以发信号给消费者,通知它没有更多数据可用了(对于Iterable,一个for循环正常完成表示没有数据了;对于Observable,就是调用观察者的onCompleted方法)
生产者可以发信号给消费者,通知它遇到了一个错误(对于Iterable,迭代过程中发生错误会抛出异常;对于Observable,就是调用观察者(Observer)的onError方法)
有了这两种功能,Rx就能使Observable与Iterable保持一致了,唯一的不同是数据流的方向。任何对Iterable的操作,你都可以对Observable使用。
三、操作符
大多数操作符操作可观察对象并返回可观察对象。这允许您在一个链中一个接一个地应用这些操作符。链中的每个操作符都修改由前一个操作符的操作所产生的Observable。
一个可观察对象操作符链并不是独立于产生该链的原始可观察对象上操作的,而是依次操作的,每个操作符都对链中最前面的操作符生成的可观察对象进行操作。
操作符主要分为:
- 创建操作 Create、Defer、Empty、Just、Range 等
- 转换操作 Buffer、FlatMap、GroupBy、Map等
- 过滤操作 Distinct、ElementAt、Last、Skip等
- 组合操作 And、Then、Join、Merge、Zip等
- 错误处理操作 catch、Retry等
- 工具方法操作符 Delay、Do、Using等
- 条件操作符 All、SkipUntil、TakeUntil、Contains
- 数学操作符 Average、Concat、Count、Max等
- 连接操作符 Connect、Publish、Replay、RefCount等
- 转换可观察对象的操作符 To
详细分类请查看:https://reactivex.io/documentation/operators.html
四、调度器
如果你想在Observable操作符的级联中引入多线程,你可以通过指示这些操作符(或特定的Observable)对特定的scheduler进行操作来实现。
一些ReactiveX Observable操作符的变体以Scheduler作为参数。这些命令指示操作符在特定的Scheduler上执行部分或全部工作。
默认情况下,Observable和你应用到它的操作符链会在订阅方法被调用的同一个线程上完成它的工作,并通知它的观察者。SubscribeOn操作符通过指定一个可观察对象应该在其上操作的不同调度程序来改变这种行为。ObserveOn操作符指定了一个不同的Scheduler, Observable将使用这个Scheduler向它的观察者发送通知。
正如上图所示,SubscribeOn操作符指定了可观察对象将在哪个线程上开始操作,无论该操作符在操作符链中的哪个点被调用。另一方面,ObserveOn会影响Observable将使用的线程。出于这个原因,你可以在Observable操作符链中的不同位置多次调用ObserveOn,以改变某些操作符在哪个线程上操作。