我尝试使用FutureBuilder
中的flutter
小部件从网络中获取一些数据。为此,我使用下面的代码:
Future<List<Product>> getWishList() async {
http.Response response = await http.post(
MY_URL,
headers: {
HttpHeaders.acceptHeader: 'application/json',
HttpHeaders.contentTypeHeader: 'application/json; charset=utf-8'
},
);
if (response.statusCode == 200) {
List<Product> ret = List();
Map<String, dynamic> result;
try {
result = json.decode(response.body);
for (var i = 0; i < result['data'].length; i++) {
ret.add(Product.fromJson(result['data'][i]));
}
return ret;
} catch (e) {
return throw Exception("Json parse error");
}
} else {
return throw Exception("network connection failed");
}
}
AND:
FutureBuilder(
future: getWishList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.connectionState == ConnectionState.done){
if(snapshot.hasError){
controller.forward(from: 0.0);
return Material(
child: Container(
margin: const EdgeInsets.only(top: 36.0),
width: double.infinity,
child: FadeTransition(
opacity: animation,
child: PButton(
onPressed: (){
setState(() {
getWishList();
});
},
child: Column(
children: <Widget>[
Icon(Icons.perm_scan_wifi,color: Colors.black,size: 76.0,),
SizedBox(height:24.0),
Text("Try again",style: TextStyle(fontSize: 16.0,color: const Color(0XFF222222)),),
],
),
),
),
),
);
}else{
return new ListView(
children: <Widget>[
GestureDetector(
onTap:(){
setState(() {
getWishList();
});
},
child: new Text("Every thing ok"))
]);
}
}else{
return Center(
child: Container(
margin: const EdgeInsets.only(top: 36.0),
child: CircularProgressIndicator()),
);
}
})
现在,http响应是否一切都很好,但是单击Try again
会在第一时间返回错误;如果再次出错,此消息将在控制台上显示:
[VERBOSE-2:shell.cc(184)] Dart错误:未处理的异常:异常: 网络连接失败 _WishListState.getWishList(package:parchino / screen / screen_wish_list.dart:127:14) _WishListState.build ... (package:parchino / screen / screen_wish_list.dart:65:33) State.setState(包:flutter / src / widgets / framework.dart:1130:30) _WishListState.build ..(package:parchino / screen / screen_wish_list.dart:64:31) GestureRecognizer.invokeCallback(包:flutter / src / gestures / recognizer.dart:102:24) TapGestureRecognizer._checkUp(包:flutter / src / gestures / tap.dart:242:9) TapGestureRecognizer.handlePrimaryPointer(包:flutter / src / gestures / tap.dart:175:7) PrimaryPointerGestureRecognizer.handleEvent(package:flutter / src / gestures / recognizer.dart:315:9) PointerRouter._dispatch(package:flutter / src / gestures / pointer_router.dart <…>
答案 0 :(得分:3)
调用setState
时,将小部件标记为Dirty,并基本上告诉框架重新构建它,但是仅在调用getWishList
之后(setState
中的那个)。由于它是async
方法,因此可以快速启动并重建小部件。
通过重建窗口小部件,您将重建FutureBuilder
,它试图评估其未来。由于future是一个函数,因此将其调用并重新调用getWishList
。
这将导致两次调用相同的方法,因此非常快速地两次调用了http服务器。这些调用可能发生冲突,并引发错误。
您不应直接在Future
中调用FutureBuilder
,而应使用previously-obtained Future
。
Future<List<Product>> myFuture;
@override
void initState() {
myFuture = getWishList();
super.initState();
}
Future<List<Product>> getWishList() async {
//Do your stuff
}
然后在您的构建中,将myFuture
设置为FutureBuilder
的未来,并在您的setState
中,再次设置myFuture
:
FutureBuilder(
future: myFuture,
builder: (BuildContext context, AsyncSnapshot snapshot) {
//...
setState(() {
myFuture = getWishList();
});
//...
}
);
这将使setState
在myFuture
中树立新的未来,并要求小部件自行重建。重建FutureBuilder
时,它将求值myFuture
而不是再次调用http。