flutter开发核心
摘要
flutter开发核心 Future/stream/bloc
Future(异步操作)
Future有三种状态未完成、完成带有值、完成带有异常,使用Future可以简化事件任务。Dart中,可以使用Future对象来表示异步操作的结果,Future返回类型是Future
有三种方法处理Future的结果:
then: 处理操作执行结果或者错误并返回一个新的Future catchError: 注册一个处理错误的回调 whenComplete
,无论错误还是正确,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<String> getStr()async{
var str = HttpRequest.getString('www.fgyong.cn');
return str;
}
使用http请求地址www.fgyong.cn获取数据,然后返回。如何接收文本呢?
其实很简单,只需要使用await关键字即可,用来注册then回调。
main(List<String> args) async {
String string = await getStr();
print(string);
}
等同于
main(List<String> args) async {
getStr().then((value) {
print(value);
});
}
stream—连续异步操作
如果Future表示单个计算的结果,则流是一系列结果。
侦听流以获取有关结果(数据和错误)以及流关闭的通知。还可以在收听流时暂停播放或在流完成之前停止收听。
可以说Future 用于处理单个异步操作,Stream 用来处理连续的异步操作。
Stream 分单订阅流和广播流。
单订阅流在发送完成事件之前只允许设置一个监听器,并且只有在流上设置监听器后才开始产生事件,取消监听器后将停止发送事件。即使取消了第一个监听器,也不允许在单订阅流上设置其他的监听器。广播流则允许设置多个监听器,也可以在取消上一个监听器后再次添加新的监听器。
Stream 有同步流和异步流之分。
它们的区别在于同步流会在执行 add,addError 或 close 方法时立即向流的监听器 StreamSubscription 发送事件,而异步流总是在事件队列中的代码执行完成后在发送事件。
在 Dart 有几种方式创建 Stream
- 使用 async* 函数,函数标记为 async *,我们可以使用 yield 作为关键字并返回 Stream 数据
- 从现有的生成一个新的流 Stream,使用 map,where,takeWhile 等方法。
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
yield i;
}
}
Stream stream = countStream(10);
stream.listen(print);
- 使用 StreamController。
StreamController<Map> _streamController = StreamController(
onCancel: () {},
onListen: () {},
onPause: () {},
onResume: () {},
sync: false,
);
Stream _stream = _streamController.stream;
- 使用 Future 对象生成
Future<int> _delay(int seconds) async {
await Future.delayed(Duration(seconds: seconds));
return seconds;
}
List<Future> 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<StreamCounter> {
// 创建一个 StreamController
StreamController<int> _counterStreamController = StreamController<int>(
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: <Widget>[
Text('You have pushed the button this many times:'),
// 使用 StreamBuilder 显示和更新 UI
StreamBuilder<int>(
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: <Widget>[
FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
SizedBox(width: 24.0),
FloatingActionButton(
onPressed: _closeStream,
tooltip: 'Close',
child: Icon(Icons.close),
),
],
),
);
}
}
bloc—状态管理
上文了解到stream,是使用bloc的必要知识。bloc的一个基础使用是Cubit,Cubit类似是bloc的简化版,在一些小的项目上可以使用Cubit。项目维护的数据多使用Bloc最好,下面写的是bloc核心知识和使用案例
bloc处理关系图:
Bloc模式
bloc:逻辑层 state:数据层 event:所有的交互事件 view:页面
Bloc模板
view:默认添加了一个初始化事件
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<CounterBloc>(context);
return Container();
}
}
bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState().init());
@override
Stream<CounterState> mapEventToState(CounterEvent event) async* {
if (event is InitEvent) {
yield await init();
}
}
Future<CounterState> init() async {
return state.clone();
}
}
event
abstract class CounterEvent {}
class InitEvent extends CounterEvent {}
state
class CounterState {
CounterState init() {
return CounterState();
}
CounterState clone() {
return CounterState();
}
}