Flutter异步编程笔记
来自专栏:掘金专栏
单线程下的异步模型
概念
同步和异步
同步:同一时间线,单一任务线,按时序执行
异步:同一时间线,多条任务线,按时序执行
任务的状态
未完成 完成但错误 完成且正确
单线程中的异步任务
任务分配
不阻塞任务完成的非冲突事件,可开新的任务线
异步的特点
尽可能的在最短时间完成任务
异步的回调函数
在某任务完成后,触发任务完成后的事件。该事件可以是我们预知任务完成后,该做的事件。
Dart语言中的异步
异步任务
异步任务,不会阻塞与自己无关的任务。
异步模型的延伸
单线程异步模型的局限性
单一线程没法,多开线程,完成多个需要自己完成的任务
多线程与异步的关系
多个线程,分发自己的任务给其他,完成自己的任务
Dart中如何解决单线程异步模型的局限性
移动/桌面客户端大多是网络、数据库访问等io密集型的任务
io密集型就是设备的资源交换密集
cpu密集型就是设备的计算资源占比大
Future类的使用
分析Future类
认识Future对象
- sky_engine
- async
- future.dart
Future可以指定一个泛型,该类型就是期待的结果。
Future对象是在任务创建之前就产生的,对未来的结果我们是未知的,可能是成功也可能是失败。
我们通过then和catchError方法监听Future对象最终的结果,结果可以是异常,也可以是成功。
Future对任务回调的监听
- then 成功后的监听方法
- catchError 异常后的监听方法
- whenComplete 无论成功/异常的监听方法
异步任务的异常抓取
期待返回值,判断返回值。
认识异步异常抓取
catchError中onError的细节
dart
Future<T> catchError(Function onError, {bool test(Object error)?});
Future. delayed(
const Duration(seconds: 1),
() => throw 401,
).then((value) {
throw 'Unreachable';
}).catchError((err) {
print('Error: $err'); // Prints 401.
}, test: (error) {
return error is int && error >= 400;
});
FutureOr对象
该类型代表Future<T>
和T
类型。也就是说,它是一类两型的特殊存在。
catchError第二参: test
判断是否error返回的条件
异步成功的回调方法
then方法的返回值
dart
/// 返回值为泛型R
Future<R> then<R>(FutureOr<R> onValue(T value), {Function? onError});
then方法中的onError
如果使用了onError那么catchError就会失效
whenComplete 方法
dart
Future<T> whenComplete(FutureOr<void> action());
任务结束时候需要执行的动作
async/await关键字的使用
使用await关键字修饰Future对象后,返回值是结果类型
async/await 使用的注意点
后面的代码是否需要await,会影响一个程序的丝滑性
Future总结总结
Future类里的方法的第二参数,都可以对返回的参数进行一次自定义校验。
await/async语法糖按需使用。
认识Stream类的使用
分析Stream对象
Stream存在的意义
对某一个任务,想分阶段的了解任务的完成程度。
读取文件认识Stream的使用
两个重要角色:发布者和订阅者
初步认识StreamSubscription
订阅流
dart
/// 调用listen方法
StreamSubscription<T> listen(void onData(T event)?,
{Function? onError, void onDone()?, bool? cancelOnError});
/// 其他方法
// 暂停订阅
void pause([Future<void>? resumeSignal]);
// 恢复订阅
void resume();
// 终止订阅
Future<void> cancel();
综合理解Stream的使用
场景分析
红绿灯案例,写在flutter_study里面了
灯状态
dart
const int _kAllowMaxCount = 10;
const int _kWaitMaxCount = 3;
const int _kDenialMaxCount = 10;
enum SignalType {
denial, // 拒绝 - 红灯
allow, // 允许 - 绿灯
wait, // 等待 - 黄灯
}
class SignalState {
final int counter;
final SignalType type;
SignalState({
required this.counter,
required this.type,
});
SignalState next() {
if (counter > 1) {
return SignalState(type: type, counter: counter - 1);
} else {
switch (type) {
case SignalType.allow:
return SignalState(
type: SignalType.denial, counter: _kDenialMaxCount);
case SignalType.denial:
return SignalState(type: SignalType.wait, counter: _kWaitMaxCount);
case SignalType.wait:
return SignalState(type: SignalType.allow, counter: _kAllowMaxCount);
}
}
}
}
灯组件
dart
import 'package:flutter/material.dart';
import '../model/signalState.dart';
class SignalLamp extends StatelessWidget {
final SignalState state;
const SignalLamp({Key? key, required this.state}) : super(key: key);
Color get activeColor {
switch (state.type) {
case SignalType.allow:
return Colors.green;
case SignalType.denial:
return Colors.red;
case SignalType.wait:
return Colors.amber;
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(30),
),
child: Wrap(
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 15,
children: [
lamp(color: state.type == SignalType.denial ? activeColor : null),
lamp(color: state.type == SignalType.wait ? activeColor : null),
lamp(color: state.type == SignalType.allow ? activeColor : null),
],
),
),
Text(
state.counter.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 50,
color: activeColor,
),
)
],
);
}
/// 单个信号灯
Widget lamp({Color? color}) {
return Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: color ?? Colors.grey.withOpacity(0.8),
shape: BoxShape.circle,
),
);
}
}
信号灯页面
dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_study/StreamUse/widgets/signalLamp.dart';
import 'model/signalState.dart';
void main() {
runApp(const App());
}
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
final StreamController<SignalState> streamController = StreamController();
SignalState _signalState = SignalState(counter: 10, type: SignalType.denial);
bool hasError = false;
@override
void initState() {
super.initState();
streamController.stream.listen(
emit,
onError: (err) async {
print(err);
renderError();
await Future.delayed(const Duration(seconds: 3));
fixError();
emit(_signalState.next());
},
// 如果 cancelOnError = true ,在监听到异常之后,就会取消监听 stream ,也就是说之后控制器添加的元素就不会触发监听了
cancelOnError: false,
);
streamController.add(_signalState);
}
@override
void dispose() {
super.dispose();
streamController.close();
}
void renderError() {
hasError = true;
setState(() {});
}
void fixError() {
hasError = false;
}
void emit(SignalState state) async {
_signalState = state;
setState(() {});
await Future.delayed(const Duration(seconds: 1));
SignalState nextState = state.next();
if (nextState.counter == 7 && nextState.type == SignalType.denial) {
streamController.addError(Exception('Error Signal State'));
} else {
streamController.add(nextState);
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(builder: (context, child) {
return Scaffold(
body: Center(
child: !hasError
? SignalLamp(state: _signalState)
: const Text('Error Signal State')),
);
});
}
}
异步生成器函数与Stream
Stream与Iterable
- Iterable在时间和空间上都对元素保持持有关系
- Stream只是在时间上监听若干元素的到来,并不在任意时刻都持有元素,更不会在空间上保持持有关系
通过异步生成器函数获取Stream对象
dart
class SignalStream{
SignalState _signalState = SignalState(counter: 10, type: SignalType.denial);
/// async* 修饰的方法需要返回一个Stream对象
Stream<SignalState> createStream({int count = 100}) async*{
for(int i = 0 ; i < count; i++){
await Future.delayed(const Duration(seconds: 1));
_signalState = _signalState.next();
/// yield 关键字产出泛型结果对象
yield _signalState;
}
}
}