Flutter的状态管理
# 前言
随着Rect,Vue的普遍使用,响应式编程的理念也随之流行.不像在Android中的命令式编程,需要手动指定View展示. 响应式编程的设计思路是数据和视图分离,由数据映射视图的渲染.
Flutter在开发之初就大量借鉴了Rect的设计经验,在Flutter的Widget是不可变的(immutable),
# 为什么使用状态管理
当我们在
# 一,Dart 和 Flutter 内置支持
# setState
setState((){
_model = model;
}); // mounted
2
3
最重要的方式 setState,支持规模较小的程序足够了,所有其它方式最终都需要调用 setState。
# (方法回调)Function callback
Dart Function 足够灵活,还支持模版参数。
typedef FooChanged = void Function(int);
typedef ValueChanged<T> = void Function(T value);
2
3
单向变更通知,可以和ObserverList结合支持多个订阅者。 Flutter 内置 ChangeNotifier, ValueNotifier 都可以认为是类似方案。
# Delegate
可以认为是多个回调函数,其他语言里都有类似模式,名称似乎来源于 Objective-C。实际例子.
abstract class SpiderDelegate {
/// category is null, crawl book whole site
/// category not null, crawl book under the category
void onBook(Book book, {Site site, Category category});
void onChapter(Book book, Chapter chapter);
}
2
3
4
5
6
7
# Sigslot
源自 Qt 里的经典编程模式,Dart 可以轻易实现。这种方式在 Flutter 里可能根本不会有太多应用,但是由于 Sigslot 在 C++ 领域具有举足轻重的地位,属于界面数据和逻辑解耦合的王者,boost::signal(2)就是明证,在这里列出纯属凑数(本人也实现了一个).
typedef ValueCallback<E> = void Function(E value);
abstract class Signable<E> {
// Signable<bool> someValue;
/// Register a closure to be called when the object notifies its listeners.
void connect(ValueCallback<E> listener);
/// Remove a previously registered closure from the list of closures that the
/// object notifies.
void disconnect(ValueCallback<E> listener);
/// sink value changed
void emit(E value);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
使用方法类似
Signal<String> signalString;
signalString.connect((String str) {
// got the `str` changed here
});
2
3
4
5
# 二 ,包-外部实现
# pkg:scoped_model
个人以为是最佳方案,源自 Fuchsia 代码,在其中广泛使用,设置程序几乎都是这个模式,后来独立为 package,包括注释也只有 287 行代码。由于 Fuchsia App 结构都是后台Service+前台UI,这个方案绝对是最合适的方案。使用 InheritedWidget 实现,性能不可能更好. 例子太多,Flutter 官方 samples 里也有链接.
# pkg:provide
出自 Flutter dev team,绝对的官方了,总共代码 675行。实现方式和 scoped_model 类似,增加 Providers,Provider 支持 Stream.
return Column(children: [
// Simplest way to retrieve the provided value.
//
// Each time the counter changes, this will get rebuilt. This widget
// requires the value to be a Listenable or a Stream. Otherwise
Provide<Counter>(
builder: (context, child, counter) => Text('${counter.value}'),
),
// This widget gets the counter as a stream of changes.
// The stream is filtered so that this only rebuilds on even numbers.
StreamBuilder<Counter>(
initialData: currentCounter,
stream: Provide.stream<Counter>(context)
.where((counter) => counter.value % 2 == 0),
builder: (context, snapshot) =>
Text('Last even value: ${snapshot.data.value}')),
// This button just needs to call a method on Counter. No need to rebuild
// it as the value of Counter changes. Therefore, we can use the value of
// `Provide.value<Counter>` from above.
FlatButton(child: Text('increment'), onPressed: currentCounter.increment),
Text('Another widget that does not depend on the Counter'),
]);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# flutter-provide
可以认为这个比 provide 更早,功能更丰富,实现依然是 InheritedWidget。可能不会有太广泛使用,但是在时间上有历史意义,故列出.
# RxDart, Fish-Redux
看过以上各种实现后,我不知道还有什么理由一定要用 RxDart 之类重量级的实现。程序结构会被绑架,学习曲线也更高。不得不提 Bloc 是个另类,使用 RxDart 了,但是做到更简洁,对 Infinite List 等也有较好实现.
# 总结
就好像组合是使用最多的设计模式,函数回调、类回调可能就是小规模的App最佳状态管理。稍微规模程序,数据和界面都应该分层(类似 Fuchsia App),最佳方案可能就是 scoped_model.
- 03
- 加密解密02-23