Flutter Widgets 之 FutureBuilder
ResNet详解与分析
注重:无特别申明,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,
...
)
这才是准确的用法。
更多相干浏览:
假如这篇文章有协助到您,愿望您来个“赞”并关注我的民众号,异常感谢。
《程序员的办公室日常》第一回 相识