我想知道什么时候应该使用未来的构建器。例如,如果我想发出 http 请求并在列表视图中显示结果,那么一旦打开视图,我应该使用 future 构建器还是只构建一个ListViewBuilder
,例如:
new ListView.builder(
itemCount: _features.length,
itemBuilder: (BuildContext context, int position) {
...stuff here...
}
此外,如果我不想构建列表视图,而是构建一些更复杂的东西,如圆形图表,我是否应该使用未来的构建器?
希望它足够清楚!
FutureBuilder
删除样板代码。
假设您想在页面启动时从后端获取一些数据并显示加载器,直到数据出现。
列表生成器的任务:
- 有两个状态变量,
dataFromBackend
和isLoadingFlag
- 启动时,设置
isLoadingFlag = true
,并在此基础上显示loader
。 - 数据到达后,使用从后端获取的数据设置数据并设置
isLoadingFlag = false
(显然setState
内部( - 我们需要在小部件创建中有一个
if-else
。如果isLoadingFlag
true
,则显示loader
否则显示data
。失败时,显示错误消息。
未来建设者的任务:
- 在
future
未来构建器中提供异步任务 - 基于
connectionState
,显示消息(loading
,active(streams)
,done
( - 基于
data(snapshot.hasError)
, 显示视图
未来建设者的优点
- 不使用两个状态变量和
setState
- 响应式编程(
FutureBuilder
将负责在数据到达时更新视图(
例:
FutureBuilder<String>(
future: _fetchNetworkCall, // async work
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return Text('Loading....');
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
return Text('Result: ${snapshot.data}');
}
},
)
性能影响:
我只是研究了FutureBuilder
代码,以了解使用它对性能的影响。
- FutureBuilder只是一个
StatefulWidget
,其state
变量是_snapshot
- 初始状态为
_snapshot = AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData);
- 它订阅了我们通过构造函数发送的
future
并在此基础上更新state
。
例:
widget.future.then<void>((T data) {
if (_activeCallbackIdentity == callbackIdentity) {
setState(() {
_snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data);
});
}
}, onError: (Object error) {
if (_activeCallbackIdentity == callbackIdentity) {
setState(() {
_snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error);
});
}
});
因此,FutureBuilder
是我们通常所做的事情的包装器/样板,因此不应有任何性能影响。
FutureBuilder 示例
-
当您想在异步调用后使用小部件时,请使用
FutureBuilder()
class _DemoState extends State<Demo> { @override Widget build(BuildContext context) { return FutureBuilder<String>( future: downloadData(), // function where you call your api builder: (BuildContext context, AsyncSnapshot<String> snapshot) { // AsyncSnapshot<Your object type> if( snapshot.connectionState == ConnectionState.waiting){ return Center(child: Text('Please wait its loading...')); }else{ if (snapshot.hasError) return Center(child: Text('Error: ${snapshot.error}')); else return Center(child: new Text('${snapshot.data}')); // snapshot.data :- get your object which is pass from your downloadData() function } }, ); } Future<String> downloadData()async{ // var response = await http.get('https://getProjectList'); return Future.value("Data download successfully"); // return your response } }
在 future builder 中,它调用future 函数来等待结果,一旦它产生结果,它就会调用我们构建小部件的构建器函数。
异步快照有 3 种状态:
- 连接状态.none= 在此状态下,未来为空
- connectionState.wait= [future] 不为空,但尚未完成
- connectionState.done= [future] 不为空,并且已完成。如果将来成功完成,则 [AsyncSnapshot.data] 将设置为将来完成的值。如果完成但出现错误,则 [AsyncSnapshot.hasError] 将为 true
FutureBuilder是一个小部件,它将帮助您执行一些异步函数,并根据该函数的结果更新您的UI。
我列出了一些用例,为什么你会使用FutureBuilder?
-
如果要在异步任务后渲染小部件,请使用它。
-
我们可以通过简单地使用
ConnectionState.waiting
来处理加载过程 -
不需要任何自定义错误控制器。可以简单地处理错误
dataSnapshot.error != null
-
由于我们可以在构建器中处理异步任务,因此不需要任何
setState(() { _isLoading = false; });
当我们使用 FutureBuilder 小部件时,我们需要检查未来状态,即未来是否已解决等等。有以下各种状态:
-
ConnectionState.none:
表示未来为空,初始数据用作默认值。 -
ConnectionState.active:
这意味着未来不是空的,但还没有解决。 -
ConnectionState.waiting:
这意味着未来正在得到解决,我们将很快得到结果。 -
ConnectionState.done:
这意味着未来已经解决。
一个简单的实现
这里 OrdersProvider 是一个提供程序类,fetchAndSetOrders(( 是该提供程序类的方法。
body: FutureBuilder(
future: Provider.of<OrdersProvider>(context, listen: false)
.fetchAndSetOrders(),
builder: (context, dataSnapshot) {
if (dataSnapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
if (dataSnapshot.error != null) {
return Center(
child: Text('An error occured'),
);
} else {
return Consumer<OrdersProvider>(
builder: (context, orderData, child) => ListView.builder(
itemCount: orderData.orders.length,
itemBuilder: (context, i) => OrderItem(orderData.orders[i]),
),
);
}
}
},
),