Future
有三种状态未完成
、完成带有值
、完成带有异常
,使用Future
可以简化事件任务。Dart中,可以使用Future
对象来表示异步操作的结果,Future返回类型是Future
有三种方法处理Future的结果:
使用then来回调,场景使用:UI需要接口的数据,一些异步执行函数
# demo1
main() {
Future f1 = new Future(() {
print("我是第一个");
});
f1.then((_) => print("f1 then"));
print("我是main");
}
# print:
# 我是main
# 我是第一个
# f3 then
Future和async/await结合使用
使用链式调用的方式把多个future连接在一起,会严重降低代码的可读性。使用async和await关键字实现异步的功能。async和await可以帮助我们像写同步代码一样编写异步代码
Future getStr()async{
var str = HttpRequest.getString('www.fgyong.cn');
return str;
}
使用http
请求地址www.fgyong.cn
获取数据,然后返回。如何接收文本呢?
其实很简单,只需要使用await
关键字即可,用来注册then
回调。
main(List args) async {
String string = await getStr();
print(string);
}
等同于
main(List args) async {
getStr().then((value) {
print(value);
});
}
如果Future
表示单个计算的结果,则流是一系列结果。
侦听流以获取有关结果(数据和错误)以及流关闭的通知。还可以在收听流时暂停播放或在流完成之前停止收听。
可以说Future
用于处理单个异步操作,Stream
用来处理连续的异步操作。
Stream
分单订阅流和广播流。
单订阅流在发送完成事件之前只允许设置一个监听器,并且只有在流上设置监听器后才开始产生事件,取消监听器后将停止发送事件。即使取消了第一个监听器,也不允许在单订阅流上设置其他的监听器。广播流则允许设置多个监听器,也可以在取消上一个监听器后再次添加新的监听器。
Stream
有同步流和异步流之分。
它们的区别在于同步流会在执行 add
,addError
或 close
方法时立即向流的监听器 StreamSubscription
发送事件,而异步流总是在事件队列中的代码执行完成后在发送事件。
在 Dart 有几种方式创建 Stream
async*
函数,函数标记为 async *
,我们可以使用 yield
作为关键字并返回 Stream
数据Stream
,使用 map
,where
,takeWhile
等方法。 Stream countStream(int to) async* {
for (int i = 1; i <= to; i++) {
yield i;
}
}
Stream stream = countStream(10);
stream.listen(print);
StreamController
。 StreamController
Future
对象生成 Future _delay(int seconds) async {
await Future.delayed(Duration(seconds: seconds));
return seconds;
}
List futures = [];
for (int i = 0; i < 10; i++) {
futures.add(_delay(3));
}
Stream _futuresStream = Stream.fromFutures(futures);
我们在实际的开发过程中,基本都是使用的StreamContoller
来创建流。监听使用StreamBuilder,当流发生变化时执行,例子:
import 'dart:async';
import 'package:flutter/material.dart';
class StreamCounter extends StatefulWidget {
@override
_StreamCounterState createState() => _StreamCounterState();
}
class _StreamCounterState extends State {
// 创建一个 StreamController
StreamController _counterStreamController = StreamController(
onCancel: () {
print('cancel');
},
onListen: () {
print('listen');
},
);
int _counter = 0;
Stream _counterStream;
StreamSink _counterSink;
// 使用 StreamSink 向 Stream 发送事件,当 _counter 大于 9 时调用 close 方法关闭流。
void _incrementCounter() {
if (_counter > 9) {
_counterSink.close();
return;
}
_counter++;
_counterSink.add(_counter);
}
// 主动关闭流
void _closeStream() {
_counterStreamController.close();
}
@override
void initState() {
super.initState();
_counterSink = _counterStreamController.sink;
_counterStream = _counterStreamController.stream;
}
@override
void dispose() {
super.dispose();
_counterSink.close();
_counterStreamController.close();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stream Counter'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('You have pushed the button this many times:'),
// 使用 StreamBuilder 显示和更新 UI
StreamBuilder(
stream: _counterStream,
initialData: _counter,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(
'Done',
style: Theme.of(context).textTheme.bodyText2,
);
}
int number = snapshot.data;
return Text(
'$number',
style: Theme.of(context).textTheme.bodyText2,
);
},
),
],
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
SizedBox(width: 24.0),
FloatingActionButton(
onPressed: _closeStream,
tooltip: 'Close',
child: Icon(Icons.close),
),
],
),
);
}
}
上文了解到stream,是使用bloc的必要知识。bloc的一个基础使用是Cubit,Cubit类似是bloc的简化版,在一些小的项目上可以使用Cubit。项目维护的数据多使用Bloc最好,下面写的是bloc核心知识和使用案例
bloc处理关系图:
Bloc模板
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => CounterBloc()..add(InitEvent()),
child: Builder(builder: (context) => _buildPage(context)),
);
}
Widget _buildPage(BuildContext context) {
final bloc = BlocProvider.of(context);
return Container();
}
}
class CounterBloc extends Bloc {
CounterBloc() : super(CounterState().init());
@override
Stream mapEventToState(CounterEvent event) async* {
if (event is InitEvent) {
yield await init();
}
}
Future init() async {
return state.clone();
}
}
abstract class CounterEvent {}
class InitEvent extends CounterEvent {}
class CounterState {
CounterState init() {
return CounterState();
}
CounterState clone() {
return CounterState();
}
}