Flutter示例系列(二)之状态管理-肆(RxDart)

开发环境:
Mac OS 10.14.5
VSCode 1.36.1
Flutter 1.9.1+hotfix.2

前言

前面已经有 Flutter示例系列(二)之状态管理-壹(scoped_model)、 Flutter示例系列(二)之状态管理-贰(fish-redux)和 Flutter示例系列(二)之状态管理-叁(Bloc)。

基于ReactiveX,很多语言目前都有Rx的版本。由于Rx同出一脉,所以之前用过其他语言的Rx版本,可能比较好上手。当然很遗憾,我还没用过(哈哈哈哈哈哈哈哈哈)下面就一起来瞅一瞅。

概念

RxDart 是基于 ReactiveX 的响应式函数编程库。Dart本身有 Stream API,RxDart在其上增加了其他方法。在 Dart基础语法之异步支持 中(见公众号:Flutter小同学),简单描述了Stream的用法,在 Dart异步编程:Streams(见公众号:Flutter小同学) 中,对Stream进行了介绍。

API预览

  • Observable
  • PublishSubject
  • BehaviorSubject
  • ReplaySubject

1. Observable
RxDart的 Observable 继承自 Stream。

  • 所有在Stream上定义的方法,Observable上同样存在
  • 以Stream作为输入的API,也可以传递 Observables

示例:

new Observable(new Stream.fromIterable([1]))
  .interval(new Duration(seconds: 1))
  .flatMap((i) => new Observable.just(2))
  .take(1)
  .listen(print); // prints 2

Observable 类和运算符 是对Stream和StreamTransformer类的简单包装。所有的基础实现都可以与Observable类一起使用。

Observable与Stream的区别?
1.Cold Observable是单订阅。除非是hot(又称广播) Stream,否则仅可监听Observable一次。如果尝试监听两次会有异常抛出。如果需要监听多次,可以创建一个返回stream新实例的工厂方法。

2.大多数方法如 first 和 last 不会返回一个 Single或者Observable,但必定返回Future。可以使用 myFuture.asStream() 轻松转换成 Stream。

3.当有错误发生,Stream默认不关闭。在Rx中,错误会导致Observable终止,除非被其他操作打断。其实Dart有这种机制,当错误发生时将创建的streams关闭,但是大多数没有显示这一行为。

4.Streams默认异步,但是Observable默认同步,除非在不同的计划程序上制定工作。也可创建同步的Streams。

5.当使用广播Streams(类似Hot Observable)时,注意 onListen 仅在第一次监听到广播Stream时被调用。

2. PublishSubject
就像普通的广播 StreamController一样,但是返回的是一个 Observable 而不是 Stream。

允许向监听者发送数据、错误和完成的事件。

默认情况下,PublishSubject 是一个广播(又称hot)控制器,可多次订阅。

示例:

final subject = new PublishSubject<int>();

// observer1 will receive all data and done events
subject.stream.listen(observer1);
subject.add(1);
subject.add(2);

// observer2 will only receive 3 and done event
subject.stream.listen(observe2);
subject.add(3);
subject.close();

继承链:
Object > Observable > Subject > PublishSubject

3. BehaviorSubject
作为一个特殊的StreamController,捕获添加进控制器的最新项,并且作为第一项发送给新的监听者。

允许向监听者发送数据、错误和完成的事件。把添加进来的最新项发送给新的监听者,之后,新事件将适当的发送给监听者。如果没有新项加入,可能提供原始值。

默认情况下,BehaviorSubject 是一个广播(又称hot)控制器,可多次订阅。

示例:

final subject = new BehaviorSubject<int>();

subject.add(1);
subject.add(2);
subject.add(3);

subject.stream.listen(print); // prints 3
subject.stream.listen(print); // prints 3
subject.stream.listen(print); // prints 3

返回原始值的示例:

final subject = new BehaviorSubject<int>.seeded(1);

subject.stream.listen(print); // prints 1
subject.stream.listen(print); // prints 1
subject.stream.listen(print); // prints 1

继承链:
Object > Observable > Subject > BehaviorSubject

4. ReplaySubject
作为一个特殊的StreamController,捕获所有已被添加的项,作为第一项发送给新的监听者。

允许向监听者发送数据、错误和完成的事件。会存储被添加进来的项,并发送给监听者,之后,新事件将适当的发送给监听者。可以限制存储的最大数量。

默认情况下,ReplaySubject 是一个广播(又称hot)控制器,可多次订阅。

示例:

final subject = new ReplaySubject<int>();

subject.add(1);
subject.add(2);
subject.add(3);

subject.stream.listen(print); // prints 1, 2, 3
subject.stream.listen(print); // prints 1, 2, 3
subject.stream.listen(print); // prints 1, 2, 3

限制大小的示例:

final subject = new ReplaySubject<int>(maxSize: 2);

subject.add(1);
subject.add(2);
subject.add(3);

subject.stream.listen(print); // prints 2, 3
subject.stream.listen(print); // prints 2, 3
subject.stream.listen(print); // prints 2, 3

继承链:
Object > Observable > Subject > ReplaySubject

Demo

创建项目
详情见 Flutter示例系列(一)之创建项目

创建 git_search_rxdart 项目,用于搜索github。注释详情参考Demo。

在 pubspec.yaml 文件中引入 rxdart 和 http 依赖库:

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  rxdart: ^0.22.2
  http: ^0.11.3+17

github_api.dart
创建 GithubAPI类,用于请求数据,并对已获取的内容进行缓存。

还创建SearchResultItem(项目model) 和 SearchResult(mdoel集合) 类。

组件
empty_result_widget.dart:搜索结果为空的组件
search_error_widget.dart:搜索失败的组件
search_intro_widget.dart:输入关键词的组件
search_loading_widget.dart:正在加载的组件
search_result_widget.dart:展示搜索结果的组件
github_widget.dart:整个页面(后续完成)的组件

GitHub_state.dart
创建SearchState类及其子类,定义搜索状态。
包含子类:
SearchLoading:正在加载的状态
SearchError:搜索失败的状态
SearchNoTerm:搜索无结果的状态
SearchPopulated:搜索有结果的状态
SearchEmpty:搜索结果为空的状态

github_bloc.dart
创建 SearchBloc 类,进行状态管理。

定义实例变量 onTextChanged,将文本内容放入Sink

final Sink<String> onTextChanged;

定义实例变量 state,存储状态变化

final Stream<SearchState> state;

定义工厂方法,供外界调用并初始化SearchBloc。

factory SearchBloc(GithubAPI api) 

其他部分实现查看代码。

github_widget.dart
创建 SearchScreen类,并在此初始化 SearchBloc类。

 bloc = SearchBloc(widget.api);

使用 StreamBuilder 来展示异步数据变化

StreamBuilder<SearchState>(
      stream: bloc.state,
      initialData: SearchNoTerm(),
      builder: (BuildContext context, AsyncSnapshot<SearchState> snapshot) {

其他部分实现查看代码。

总结

至此,对RxDart做了简单的介绍,并完成一个小示例。Flutter状态管理系列也告一段落。选择合适的状态管理方案,关乎整个项目的基石方向。阿里的闲鱼社区应该是国内目前最活跃的,也是切身实践使用Flutter构建应用的。

如果选择,我可能会使用 fish-redux,但是bloc和rxdart已经被广泛使用,所以选择只是方向,运用才是目的。

参考文档:
RxDart
Flutter | 状态管理拓展篇——RxDart(四)
RxDart: Magical transformations of Streams
这可能是最早的RxDart使用入门教程

=================================================================
个人博客
Github
个人公众号:Flutter小同学
个人网站

你可能感兴趣的:(#,Flutter,rxdart,flutter,dart,状态管理)