使用 FutureBuilder 时重新加载数据
Reload data when using FutureBuilder
当像下面的代码一样加载小部件时,我正在加载数据。一旦 UI 完全加载,我想添加一个刷新按钮以再次重新加载数据。
如何刷新视图?
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
var futureBuilder = new FutureBuilder(
future: _getData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else
return createListView(context, snapshot);
}
},
);
return new Scaffold(
appBar: new AppBar(
title: new Text("Home Page"),
),
body: futureBuilder,
);
}
Future<List<String>> _getData() async {
var values = new List<String>();
await new Future.delayed(new Duration(seconds: 5));
return values;
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
}
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
RaisedButton button = RaisedButton(
onPressed: () {
setState(() {});
},
child: Text('Refresh'),
);
//.. here create widget with snapshot data and with necessary button
}
您可以通过单击 FlatButton 来刷新小部件。代码如下。
class _MyHomePageState extends State<MyHomePage> {
String display;
Widget futureBuilder() {
return new FutureBuilder<String>(builder: (context, snapshot) {
// if(snapshot.hasData){return new Text(display);} //does not display updated text
if (display != null) {
return new Text(display);
// return your createListView(context, snapshot);
}
return new Text("no data yet");
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Home Page"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(onPressed: () async{
result = await _getData();
print(result);
// Result will be your json response
setState(() {
display = result; //assign any string value from result to display variable.
});
},
child: new Text("Get Data")
),
futureBuilder()
],
),
),
);
}
Future<List<String>> _getData() async {
var values = new List<String>();
await new Future.delayed(new Duration(seconds: 5));
return values;
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
}
}
我对此进行了深入研究,并没有那么困难。构建器会在更改未来时正确重建(如果您使用 setState
触发更改)。问题是,hasData
和 hasError
在响应返回之前不会重置。但是我们可以使用 connectionState
代替。
final builder = FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return _buildLoader();
}
if (snapshot.hasError) {
return _buildError();
}
if (snapshot.hasData) {
return _buildDataView();
}
return _buildNoData();
});
这里是关于这个问题的 post 和一个显示问题和解决方案的链接存储库:
https://www.greycastle.se/reloading-future-with-flutter-futurebuilder/
我所做的对我有用的是在 setState() 中再次调用 future 函数。
在您的示例中,它看起来像这样。
首先,您将 _getData() 未来函数分配给具有相同 return 类型的变量 (_myData),之后,您可以在 setState() 中覆盖它的值,这将重建 UI 因此 运行 又是未来。
在代码中它看起来像这样。(以你为例):
class _MyHomePageState extends State<MyHomePage> {
Future<List<String>> _myData = _getData(); //<== (1) here is your Future
@override
Widget build(BuildContext context) {
var futureBuilder = new FutureBuilder(
future: _myData; //<== (2) here you provide the variable (as a future)
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return Column(
children: [
Icon(Icons.error),
Text('Failed to fetch data.'),
RaisedButton(
child: Text('RETRY'),
onPressed: (){
setState(){
_myData = _getData(); //<== (3) that will trigger the UI to rebuild an run the Future again
}
},
),
],
);
else
return createListView(context, snapshot);
}
},
);
return new Scaffold(
appBar: new AppBar(
title: new Text("Home Page"),
),
body: futureBuilder,
);
}
当像下面的代码一样加载小部件时,我正在加载数据。一旦 UI 完全加载,我想添加一个刷新按钮以再次重新加载数据。
如何刷新视图?
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
var futureBuilder = new FutureBuilder(
future: _getData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else
return createListView(context, snapshot);
}
},
);
return new Scaffold(
appBar: new AppBar(
title: new Text("Home Page"),
),
body: futureBuilder,
);
}
Future<List<String>> _getData() async {
var values = new List<String>();
await new Future.delayed(new Duration(seconds: 5));
return values;
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
}
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
RaisedButton button = RaisedButton(
onPressed: () {
setState(() {});
},
child: Text('Refresh'),
);
//.. here create widget with snapshot data and with necessary button
}
您可以通过单击 FlatButton 来刷新小部件。代码如下。
class _MyHomePageState extends State<MyHomePage> {
String display;
Widget futureBuilder() {
return new FutureBuilder<String>(builder: (context, snapshot) {
// if(snapshot.hasData){return new Text(display);} //does not display updated text
if (display != null) {
return new Text(display);
// return your createListView(context, snapshot);
}
return new Text("no data yet");
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Home Page"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(onPressed: () async{
result = await _getData();
print(result);
// Result will be your json response
setState(() {
display = result; //assign any string value from result to display variable.
});
},
child: new Text("Get Data")
),
futureBuilder()
],
),
),
);
}
Future<List<String>> _getData() async {
var values = new List<String>();
await new Future.delayed(new Duration(seconds: 5));
return values;
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
}
}
我对此进行了深入研究,并没有那么困难。构建器会在更改未来时正确重建(如果您使用 setState
触发更改)。问题是,hasData
和 hasError
在响应返回之前不会重置。但是我们可以使用 connectionState
代替。
final builder = FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return _buildLoader();
}
if (snapshot.hasError) {
return _buildError();
}
if (snapshot.hasData) {
return _buildDataView();
}
return _buildNoData();
});
这里是关于这个问题的 post 和一个显示问题和解决方案的链接存储库: https://www.greycastle.se/reloading-future-with-flutter-futurebuilder/
我所做的对我有用的是在 setState() 中再次调用 future 函数。 在您的示例中,它看起来像这样。
首先,您将 _getData() 未来函数分配给具有相同 return 类型的变量 (_myData),之后,您可以在 setState() 中覆盖它的值,这将重建 UI 因此 运行 又是未来。
在代码中它看起来像这样。(以你为例):
class _MyHomePageState extends State<MyHomePage> {
Future<List<String>> _myData = _getData(); //<== (1) here is your Future
@override
Widget build(BuildContext context) {
var futureBuilder = new FutureBuilder(
future: _myData; //<== (2) here you provide the variable (as a future)
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return Column(
children: [
Icon(Icons.error),
Text('Failed to fetch data.'),
RaisedButton(
child: Text('RETRY'),
onPressed: (){
setState(){
_myData = _getData(); //<== (3) that will trigger the UI to rebuild an run the Future again
}
},
),
],
);
else
return createListView(context, snapshot);
}
},
);
return new Scaffold(
appBar: new AppBar(
title: new Text("Home Page"),
),
body: futureBuilder,
);
}