【备战春招】第13天 Flutter中的Future与FutureBuilder
2023/2/20 4:20:41
本文主要是介绍【备战春招】第13天 Flutter中的Future与FutureBuilder,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
课程名称:Flutter从入门到进阶 实战携程网App 一网打尽核心技术
课程章节:Flutter进阶提升:网络编程与数据存储技术
课程讲师:CrazyCodeBoy
课程内容
Future
Future介绍
在 Flutter 中可以借助 Future 实现异步操作。
Future 是个泛型类,可以指定类型。如果没有指定相应类型的话,则Future会使用动态的推导类型。Future<T> 类,表示一个T类型的异步操作结果。如果异步操作不需要结果,则类型为 Future<void>。
Future使用工厂构造函数来创建实例,构成构造函数具有以下特点:
- 在 Dart 中工厂构造函数的关键字是 factory;
- 与一般的构造函数不同,工厂构造函数不会自动生成实例,而是通过代码来决定返回的实例;
- 在构造方法前加上factory 关键字后就变成了工厂构造函数;
Future 有两种状态:
- pending,表示 Future异步操作正在执行,此时还没有执行结果;
- completed,执行结束,返回值有两种情况,异步执行的结果和失败的状态。
await 和 async与 Future 配合使用
await和 async 是 Dart支持异步的两个关键字:
- await,后面会跟着一个 Future,表示等待该异步任务完成后才会继续往下执行。await只能出现在异步函数内部,能够让开发人员可以像写同步代码那样来执行异步任务,而不使用回调的方式。
- async,修饰的函数是异步的,修饰的函数会返回一个 Future 对象。
示例代码:
test() async { int result = await Future.delayed(Duration(milliseconds: 2000), () { return Future.value(123); }); print('t3:' + DateTime.now().toString()); print(result); } main() { print('t1:' + DateTime.now().toString()); test(); print('t2:' + DateTime.now().toString()); }
Future 中的其它方法
Future.then()
Future.then() 接收两个函数类型的参数,第一个参数是异步执行成功的结果回调,第二个参数onError表示异步执行出现异常,返回一个Future对象。
Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
Future.catchError()
捕捉 Future 的错误的回调,并且返回一个 Future 对象。
Future.onError()
Future.catchError()回调只处理原始 Future 抛出的错误,不能处理回调函数抛出的错误,此时可以使用Future.onError()。如果catchError()与onError()同时存在,则会只调用onError()。
future.whenComplete()
在 Future 完成之后总是会调用,不管是错误导致的完成还是正常执行完毕,并且返回一个 Future 对象。then().catchError()的模式类似于try-catch,try-catch有个finally代码块,而Future.whenComplete() 相当于Future中的finally。
示例代码:
void main() { var random = Random(); Future.delayed(Duration(seconds: 3), () { if (random.nextBool()) { return 100; } else { throw 'boom!'; } }).then(print).catchError(print).whenComplete(() { print('done!'); });
Future.wait()
开发中会遇到这样的场景:网络请求A和网络请求B都完成以后,再执行代码C,此时可以使用Future.wait()。
- 如果所有 Future 都有正常结果返回。则Future的返回结果是所有指定Future的结果的集合;
- 如果其中一个或者几个 Future 发生错误,产生了error。则 Future 的返回结果是第一个发生错误的 Future 的值。
future.timeout()
完成一个异步操作可能需要很长的时间,比如:网络请求,但有时我们需要为异步操作设置一个超时时间。
void main() { new Future.delayed(new Duration(seconds: 3), () { return 1; }).timeout(new Duration(seconds: 2)).then(print).catchError(print); }
运行上述代码会看到:
TimeoutException after 0:00:02.000000: Future not completed。
FutureBuilder
FutureBuilder是一个将异步操作和异步UI更新结合在一起的类,通过FutureBuilder可以将网络请求,数据库读取等的结果更新的页面上。
FutureBuilder的构造方法
FutureBuilder 的构造方法:
FutureBuilder({Key key, Future<T> future, T initialData, @required AsyncWidgetBuilder<T> builder })
- future,是Future对象表示此构建器当前连接的异步计算;
- initialData,表示一个非空的Future完成前的初始化数据;
- builder,是AsyncWidgetBuilder类型的回调函数,是一个基于异步交互构建widget的函数;
AsyncWidgetBuilder类型:
typedef AsyncWidgetBuilder<T> = Widget Function(BuildContext context, AsyncSnapshot<T> snapshot);
其中AsyncWidgetBuilder 函数接受两个参数BuildContext context 与 AsyncSnapshot<T> snapshot,返回一个Widget。
AsyncSnapshot包含异步计算的信息,它具有以下属性:
- connectionState,枚举类型,表示与异步计算的连接状态,有四个值:none(当前没有连接到任何的异步任务),waiting(连接到异步任务并等待进行交互),active(连接到异步任务并开始交互)和done(异步任务中止);
- data,异步计算接收的最新数据;
- error,异步计算接收的最新错误对象;
AsyncSnapshot还具有hasData和hasError属性,以分别检查它是否包含非空数据值或错误值。
FutureBuilder的使用
使用FutureBuilder的基本模式,即在创建新的FutureBuilder对象时,将Future对象作为要处理的异步计算传递。 在构建器函数中,检查connectionState的值,并使用AsyncSnapshot中的数据或错误返回不同的窗口小部件。
class _MyAppState extends State<MyApp> { String showResult = ''; Future<CommonModel> fetchPost() async { final response = await http .get('https://www.devio.org/io/flutter_app/json/test_common_model.json'); Utf8Decoder utf8decoder = Utf8Decoder(); //fix 中文乱码 var result = json.decode(utf8decoder.convert(response.bodyBytes)); return CommonModel.fromJson(result); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Future与FutureBuilder实用技巧'), ), body: FutureBuilder<CommonModel>( future: fetchPost(), builder: (BuildContext context, AsyncSnapshot<CommonModel> snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: return new Text('Input a URL to start'); case ConnectionState.waiting: return new Center(child: new CircularProgressIndicator()); case ConnectionState.active: return new Text(''); case ConnectionState.done: if (snapshot.hasError) { return new Text( '${snapshot.error}', style: TextStyle(color: Colors.red), ); } else { return new Column(children: <Widget>[ Text('icon:${snapshot.data.icon}'), Text('statusBarColor:${snapshot.data.statusBarColor}'), Text('title:${snapshot.data.title}'), Text('url:${snapshot.data.url}') ]); } } }), ), ); } } class CommonModel { final String icon; final String title; final String url; final String statusBarColor; final bool hideAppBar; CommonModel( {this.icon, this.title, this.url, this.statusBarColor, this.hideAppBar}); factory CommonModel.fromJson(Map<String, dynamic> json) { return CommonModel( icon: json['icon'], title: json['title'], url: json['url'], statusBarColor: json['statusBarColor'], hideAppBar: json['hideAppBar'], ); } }
课程总结
由于StatefulWidget 会维护一个 State,当State有变动的时候会调用 didUpdateWidget()方法,重新build()。
在使用FutureBuilder时,future这个参数建议在 initState() 里初始化,不要在 build() 方法里初始化,否则会一直 rebuild()。
didUpdateWidget() 方法的源码:
@override void didUpdateWidget(FutureBuilder<T> oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.future != widget.future) { if (_activeCallbackIdentity != null) { _unsubscribe(); _snapshot = _snapshot.inState(ConnectionState.none); } _subscribe(); } }
可以看出来方法中会判断future 这个字段,然后会重复调用 inState(),重复进行rebuild()。所以一定不要在 build 方法里初始化 future 参数。
这篇关于【备战春招】第13天 Flutter中的Future与FutureBuilder的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-11有哪些好用的家政团队管理工具?
- 2025-01-11营销人必看的GTM五个指标
- 2025-01-11办公软件在直播电商前期筹划中的应用与推荐
- 2025-01-11提升组织效率:上级管理者如何优化跨部门任务分配
- 2025-01-11酒店精细化运营背后的协同工具支持
- 2025-01-11跨境电商选品全攻略:工具使用、市场数据与选品策略
- 2025-01-11数据驱动酒店管理:在线工具的核心价值解析
- 2025-01-11cursor试用出现:Too many free trial accounts used on this machine 的解决方法
- 2025-01-11百万架构师第十四课:源码分析:Spring 源码分析:深入分析IOC那些鲜为人知的细节|JavaGuide
- 2025-01-11不得不了解的高效AI办公工具API