RxDart——Dart和Flutter中的响应式编程入门

RxDart

今年年初开始尝试使用Flutter开发android APP,期间遇到了不少的坑,但总算是有惊无险。而在做Android原生开发时,RxAndroid让代码爽到飞起。为了找回那种熟悉的感觉,特意将RxDart引入到项目中。首先介绍一下RxDart是什么:
RxDart基于ReactiveX,由Dart标准库中Stream扩展而成,是一个为Dart语言提供响应式编程的库。

如何使用

添加依赖

首先在pubspec.yaml中添加依赖:

dependencies:
  rxdart: ^0.22.1+1

范例

接下来我们通过一段代码来看一下如何使用RxDart

Observable.just(1).listen(print);
>>>1
image

一行完事儿?这都是什么啊?别着急,这只是Dart语法的特性,接下来我们将上面的代码进行拆分:

//创建一个被观察者
var observable = Observable.just(1);
//创建一个观察者
var observa = (int num) {
    print(num);
};
//通过listen实现订阅
observable.listen(observa);

这下就明朗了,作为一个Android开发者,对这段代码充满亲切感。简直和RxJava一抹一样!!!

创建被观察者

RxDart提供了很多方法供我们创建Observable,除了上文中的直接使用just工厂函数从单个值中创建,还有以下几种创建方法:

  • 从一个Stream中创建:Observable(Stream.fromIterable([1, 2, 3, 4, 5])).listen(print);
  • 创建周期性事件:Observable.periodic(Duration(seconds: 1), (x) => x.toString()).listen(print);这段代码每隔一秒钟打印一个整数并加一
  • 从Future中创建:通过一个Future创建的Observable,会先等待Future执行完毕,完后发射数据,这个输出数据就是Future的执行结果,如果Future没有任何返回值,那么输出null。还可以toStream方法将Future转换为Stream然后再创建:
Observable.periodic(Duration(seconds: 1), (x) => x.toString()).listen(print);
Future<String> asyncFunction() async {
    return Future.delayed(const Duration(seconds: 10), () => "十秒后的数据");
}
Observable.fromFuture(asyncFunction()).listen(print);

代码输出如下:

image

操作符和数据变换

Rx最爽的是什么?当然是无处不在的操作符啦!我个人觉得操作符是Rx的灵魂,关于操作符原理大家可以阅读从源码查看RxJava中的map和flatMap的用法和区别去了解。下面我们通过几个常用的操作符学习一下RxDart的操作符使用方法:

过滤操作符

过滤操作符就是用来过滤掉Observable发射的一些数据,丢弃这些数据只保留过滤后的数据。

where

点了半天编辑器总是不自动补全Filter

image

竟然没有Filter操作符号了,还好有个where
我们实现一个对奇偶进行过滤的操作:

Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
      .where((num) => num % 2 == 0)
      .listen(print);
>>>2 4
skip

如果我们想跳过前三个数字,我们可以使用skip操作符:

Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
      .skip(3)
      .listen(print);
>>> 4 5
take

和skip操作相反,如果我们去掉后面三个数据,只输出前面两个数据:

Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
      .take(2)
      .listen(print);
<<<1 2
distinct

如果我们要过滤掉原始数据里重复的项:

Observable(Stream.fromIterable([1, 2, 2, 2, 3, 3, 4, 5]))
      .distinctUnique()
      .listen(print);
>>> 1 2 3 4 5

变换操作符

过滤操作符就是用来过变换Observable发射的一些数据或者Observable本身,将被变换的对象转换成为我们想要的。

map

首先说一下map,依旧是实现一个基本的数据转换,将数字翻倍:

Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
    .map((num) => num * 2)
    .listen(print);
<<<2 4 6 8 10
flatMap

接下来说一下flatMap,取出一个由数组组成的数组中的元素:

var list1 = [1, 2, 3];
var list2 = [4, 5, 6];
var list3 = [7, 8, 9];
var listAll = [list1, list2, list3];
Observable(Stream.fromIterable(listAll))
    .flatMap((listItem) => Observable(Stream.fromIterable(listItem)))
    .listen(print);
<<<1 2 3 4 5 6 7 8 9
concatMap

类似flatMap操作符,区别在于concatMap按次序连接而不是合并那些生成的Observables,然后产生自己的数据序列。
看看下面的代码:

var list1 = [1, 2, 3];
  var list2 = [4, 5, 6];
  var list3 = [7, 8, 9];
  var listAll = [list1, list2, list3];
  var changeConcatMap = (List<int> listItem) {
    print("concatMap开始变换了");
    return Observable(Stream.fromIterable(listItem));
  };
  var changeFlatMap = (List<int> listItem) {
    print("FlatMap开始变换了");
    return Observable(Stream.fromIterable(listItem));
  };
  Observable(Stream.fromIterable(listAll))
      .concatMap((listItem) => changeConcatMap(listItem))
      .listen(print);
  Observable(Stream.fromIterable(listAll))
      .flatMap((listItem) => changeFlatMap(listItem))
      .listen(print);

输出结果为:

image

结合操作符

startWith

在数据序列的开头插入一条指定的项:

var observable = Observable(Stream.fromIterable([1, 2, 3, 4, 5]));
observable.startWith(9).listen(print);
>>>9 1 2 3 4 5
merge

使用Merge操作符你可以将多个Observables的输出合并,就好像它们是一个单个的Observable一样。但是可能会让合并的Observables发射的数据交错

Observable.merge([
    Stream.fromIterable([1, 2]),
    Stream.fromIterable([3, 4])
  ]).listen(print);
>>> 1 3 2 4
combineLatest

当两个Observables中的任何一个发射了数据时,使用一个函数结合每个Observable发射的最近数据项,并且基于这个函数的结果发射数据。

var observable1 = Observable.just(1);
var observable2 = Observable.just(2);
Observable.combineLatest([observable1, observable2], (num) => num)
      .listen(print);
>>>[1,2]
mergeWith

mergeWith将多个被观察者发射的流合并成一个流。数据按照被发送的顺序传递

var observable1 = Observable.just(1);
  var observable2 = Observable.just(5);
  var observable = Observable(Stream.fromIterable([1, 2, 3, 4, 5]));
  observable
      .mergeWith([observable2,observable1])
      .listen(print);
>>> 1 5 1 2 3 4 5

结语

这只是一片RxDart使用的入门教程的。本文并未深入探讨RxDart的实现原理和逻辑,因为这些原理基本和RxJava中的类似。感兴趣的可以去关注我的RxJava系列的文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容

  • 响应式编程简介 响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者...
    长夜西风阅读 3,047评论 0 5
  • 一、RxJava操作符概述 RxJava中的操作符就是为了提供函数式的特性,函数式最大的好处就是使得数据处理简洁易...
    无求_95dd阅读 2,959评论 0 21
  • 一、RxJava操作符概述 RxJava中的操作符就是为了提供函数式的特性,函数式最大的好处就是使得数据处理简洁易...
    测天测地测空气阅读 624评论 0 1
  • 版权声明:本文为小斑马伟原创文章,转载请注明出处! 上篇简单的阐述了响应式编程的基本理论。这篇主要对响应编程进行详...
    ZebraWei阅读 2,152评论 0 2
  • RxJava正在Android开发者中变的越来越流行。唯一的问题就是上手不容易,尤其是大部分人之前都是使用命令式编...
    刘启敏阅读 1,834评论 1 7