Flutter Widgets 之 FutureBuilder

注意:无特殊说明,Flutter版本及Dart版本如下:
- Flutter版本: 1.12.13+hotfix.5
- Dart版本: 2.7.0
展示异步任务状态
当有一个Future(异步)任务需要展示给用户时,可以使用FutureBuilder控件来完成,比如向服务器发送数据成功时显示成功提示:
var _future = Future.delayed(Duration(seconds: 3), () {
return '老孟,一个有态度的程序员';
});
FutureBuilder(
future: _future,
builder: (context, snapshot) {
var widget;
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
widget = Icon(
Icons.error,
color: Colors.red,
size: 48,
);
} else {
widget = Icon(
Icons.check_circle,
color: Colors.green,
size: 36,
);
}
} else {
widget = Padding(
padding: EdgeInsets.all(20),
child: CircularProgressIndicator(),
);
}
return Center(
child: Container(
height: 100,
width: 100,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(10))),
child: widget,
),
);
},
);
效果如下:

在Future任务中出现异常如何处理,下面模拟出现异常,修改_future:
var _future = Future.delayed(Duration(seconds: 3), () {
return Future.error('');
});
效果如下:

builder是FutureBuilder的构建函数,在这里可以判断状态及数据显示不同的UI,
ConnectionState的状态包含四种:none、waiting、active、done,但我们只需要关注done状态,此状态表示Future执行完成,snapshot参数的类型是AsyncSnapshot<T>。
ListView加载网络数据
FutureBuilder还有一个比较常用的场景:网络加载数据并列表展示,这是一个非常常见的功能,在网络请求过程中显示loading,请求失败时显示失败UI,成功时显示成功UI。
模拟成功网络请求,通常会返回json字符串:
var _future = Future.delayed(Duration(seconds: 3), () {
return 'json 字符串';
});
构建FutureBuilder控件:
FutureBuilder(
future: _future,
builder: (context, snapshot) {
var widget;
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
widget = _loadingErrorWidget();
} else {
widget = _dataWidget(snapshot.data);
}
} else {
widget = _loadingWidget();
}
return widget;
},
);
构建loading控件:
_loadingWidget() {
return Center(
child: Padding(
padding: EdgeInsets.all(20),
child: CircularProgressIndicator(),
),
);
}
构建网络加载失败控件:
_loadingErrorWidget() {
return Center(
child: Text('数据加载失败,请重试。'),
);
}
数据加载成功,构建数据展示控件:
_dataWidget(data) {
return ListView.separated(
itemBuilder: (context, index) {
return Container(
height: 60,
alignment: Alignment.center,
child: Text(
'$index',
style: TextStyle(fontSize: 20),
),
);
},
separatorBuilder: (context, index) {
return Divider();
},
itemCount: 10,
);
}
效果如下:

模拟网络加载失败:
var _future = Future.delayed(Duration(seconds: 3), () {
return Future.error('');
});
效果如下:

通过上面的示例说明FutureBuilder控件极大的简化了异步任务相关显示的控件,不再需要开发者自己维护各种状态以及更新时调用State.setState。
防止FutureBuilder重绘
FutureBuilder是一个StatefulWidget控件,如果在FutureBuilder控件节点的父节点重绘rebuild,那么FutureBuilder也会重绘,这不仅耗费不必要的资源,如果是网络请求还会消耗用户的流量,这是非常糟糕的体验,如何解决这个问题?
通过源代码发现FutureBuilder重绘逻辑是这样的:
@override
void didUpdateWidget(FutureBuilder<T> oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.future != widget.future) {
if (_activeCallbackIdentity != null) {
_unsubscribe();
_snapshot = _snapshot.inState(ConnectionState.none);
}
_subscribe();
}
}
FutureBuilder在重建时判断旧的future和新的future是否相等,如果不相等才会重建,所以我们只需要让其相等即可,有人可能会以为设置的future是同一个函数,如下:
_future() async{
...
}
FutureBuilder(
future: _future(),
...
)
上面的方式是不相等的,是错误的用法,可以将_future方法赋值给变量:
var _mFuture;
@override
void initState() {
// TODO: implement initState
super.initState();
_mFuture = _future();
}
_future() async{
...
}
FutureBuilder(
future: _mFuture,
...
)
这才是正确的用法。
更多相关阅读:
- Flutter系列文章总览
- Flutter Widgets 之 Expanded和Flexible
- Flutter Widgets 之 AnimatedList
- Flutter Widgets 之 SliverAppBar
如果这篇文章有帮助到您,希望您来个“赞”并关注我的公众号,非常谢谢。

Flutter Widgets 之 FutureBuilder的更多相关文章
- 【Flutter Widgets大全】电子书开源
[Flutter Widgets大全]是老孟耗费大量精力整理的,总共有330多个组件的详细用法,开源到Github上,希望可以帮助到大家,开源不易,点个赞可不可以. [Flutter Widgets ...
- Flutter Widgets 之 InkWell 和 Ink
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 InkWell InkWell组件在用户点击时出现&quo ...
- Flutter Widgets 之 BottomNavigationBar 和 BottomNavigationBarItem
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 BottomNavigationBar 和 BottomN ...
- Flutter Widgets 之 ListWheelScrollView
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 基础用法 在展示大量数据的时候我们第一会想到使用ListV ...
- Flutter Widgets 之 RichText
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 基础用法 应用程序离不开文字的展示,因此文字的排版非常重要 ...
- Flutter Widgets 之 SnackBar
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 基础用法 应用程序有时候需要弹出消息提示用户,比如'网络连 ...
- Flutter Widgets 对话框-Dialog
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 当应用程序进行重要操作时经常需要用户进行2次确认,以避免用 ...
- Flutter Widgets
Flutter Widgets Flutter 组件 Syncfusion Flutter Widgets 所有组件均支持即装即用的 Android,iOS和 Web not free https:/ ...
- Flutter Widgets (Container/Row/Column/Image)
俗话说知己知彼百战百胜,如果对Flutter 里面的各种Widgets不了解,那你就别想将它们组合成你想要的效果.从今天开始.会把一个一个的widget 撸一遍..知道它大概的用法.效果.当你想做某个 ...
随机推荐
- 「1.0」一个人开发一个App,小程序从0到1,起航了
古有,秦.齐.楚.赵.魏.韩.燕七国争雄:今有,微信.QQ.百度.支付宝.钉钉.头条.抖音七台争霸.古有,白起.李牧.王翦.孙膑.庞涓.赵奢.廉颇驰骋疆场:今有程序员1,程序员2,程序员3…编写代码. ...
- C# 实现验证码识别,使用AspriseOCR.dll
验证码(Captcha)基于十道安全栅栏, 为网页.App.小程序开发者打造立体.全面的人机验证,最大程度地保护注册登录.活动秒杀.点赞发帖.数据保护等各大场景下的业务安全.要做自动化脚本程序,就要能 ...
- java"小心机"(1)【资源彩蛋!】
每天进步一点点,距离大腿又近一步! 阅读本文大概需要9分钟 java"小心机"系列文章在此开篇.在这,将会给你带来曾经错过.忽略或感到模糊的知识,也许它很基础,微不足道,但它能修复 ...
- HUAWEI MateBook Fn 功能键/热键切换、设置方法
原文地址:https://club.huawei.com/thread-13130964-1-1.html HUAWE MateBook E/X/D的F1.F2 等键默认是热键优先.在热键模式下,要想 ...
- isinstance 和type
推荐使用 isinstance 判断对象类型. isinstance 的用法: 语法: isinstance(object, classinfo) 其中,object 是变量,classinfo 是类 ...
- Mysql梳理-关于索引/引擎与锁
前言 最近突发新型肺炎,本来只有七天的春节假期也因为各种封锁延长到了正月十五,在家实在闲的蛋疼便重新研究了一下Mysql数据库的相关知识,特此总结梳理一下.本文主要围绕以下几点进行: 1.Mysql的 ...
- Kafka动态配置实现原理解析
问题导读 Apache Kafka在全球各个领域各大公司获得广泛使用,得益于它强大的功能和不断完善的生态.其中Kafka动态配置是一个比较高频好用的功能,下面我们就来一探究竟. 动态配置是如何设计的? ...
- SQL Server 常用的数据类型
1. 字符串数据类型 char 此数据类型可存储1~8000个定长字符串,字符串长度在创建时指定:如未指定,默认为char(1).每个字符占用1byte存储空间. nchar ...
- 安卓开发实战-记账本APP(六)
记账本APP开发---终结篇 昨天的动态数字录屏奉上:在抖音上拍了一个(ps:欢迎点赞) https://v.douyin.com/poEjmG/ 今天将图表的内容进行了制作,我用的是MPChart的 ...
- Go语言之路—博客目录
Go语言介绍 为什么你应该学习Go语言? 开发环境准备 从零开始搭建Go语言开发环境 VS Code配置Go语言开发环境 Go语言基础 Go语言基础之变量和常量 Go语言基础之基本数据类型 Go语言基 ...