0%

Dart Streams

什么是Streams?

streams就好比传送带,将物品放到一侧,他将自动运送到另一侧。我们可以将数据对象放在传送带上,他会被传送带传输。如果传送带不是无限长的(它不是一个无限的流, 例如rxjs里的interval,如果不取消订阅,他会随着时间一直流动),那么传送带的物品终会掉落。

avatar

为了避免传送带上的物品无辜掉落,我们可以做一些事情,使得物品在掉落之前实现某些价值。

avatar

Dart Streams 和 Rx

  • Rx里面的可观察对象命名未Observable,它与Dart Streams里的Stream是同等的意义,所以在可以使用Stream的任何地方赋予Observable的含义

  • listen / subscribe, 进行序列订阅,同等意义

  • listen()返回一个StreamSubscription对象,调用cancel()释放订阅

  • StreamController / Subject, 发布值,相当于在传送带的左侧添加物品,同等意义

使用StreamBuilder

不用使用initState()和setState(),flutter提供了一个方便的widget称之为StreamBuilder,它需要一个Stream和一个builder函数,只要Stream发出一个新值就会调用他,不再需要initState或dispose.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
body: Center(
child: Column(
mainAxisAligment: MainAxisAlignment.center,
children: <Widget>[
Text('demo'),
StreamBuilder<int>(
initialData: 0,
stream: _stream,
builder: (context, snappShot) {
String valueString = 'NoData';
if (snappShot != null && snappShot.hasData) {
valueString = snappShot.data.toString();
}
return Text(
valueString,
style: Theme.of(context).textTheme.display1
)
}
)
]
)
)

相对于直接订阅,使用StreamBuilder有几个明显的区别:

  • setState()在listen()时接受新值时会重建整页,而StreamBuilder只会重建他自己的widget
  • snappShot包含从Stream接收的最新数据
  • 含有一个initialData,用于第一次构建,即屏幕的第一帧,解决StreamBuilder不能在第一帧期间接收值的问题,如果snappShot无效,则返回默认Widget,适用于某些业务场景

flutter中使用BLOC模式

什么是bloc模式?

bloc[Business Logic Component]翻译过来就是业务逻辑组件,把业务逻辑抽出来,数据和ui解耦,一处改动,多处更新

avatar

上面描述的是组件的一些基本行为,【展示数据】,【发送事件】,flutter中实现Bloc的精髓就是stream,严格遵守了单一职责原则,代码解耦更好。

UI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
...
}
class CounterPage extends StateLessWidget {
@override
Widget build(BuildContext context) {
final IncrementBloc bloc = BlocProvider.of<IncrementBloc>(context);
return Scaffod(
appBar: AppBar(
title: Text('block')
),
body: Center(
child: StreamBuilder<int>(
stream: bloc._counterStream,
initialData: 0,
builder: (BuildContext context, AsyncSnapShot<int> snapshot) {
return Text('clicked ${snapshot.data} times')
}
)
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
bloc._actionSink.add(null); // 发送事件
}
)
)
}
}

Bloc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class IncrementBloc {
int _counter;
StreamController<int> _counterController = StreamController<int>();
StreamSink<int> _counterSink => _counterController.sink; // 发送数据
Stream<int> _counterStream => _counterController.stream; // stream

StreamController _actionController = StreamController();
StreamSink _actionSink => _actionController.sink;
Stream _actionStream => _actionController.stream;

void IncrementBloc() {
_counter = 0;
_actionStream.listen((data){
_counter = _counter + 1;
_counterSink.add(_counter);
});
}
}