FutureBuilder Flutter中未处理的异常

时间:2018-11-26 14:17:10

标签: dart flutter

我尝试使用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 <…>

1 个答案:

答案 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();
      });
      //...
  }
);

这将使setStatemyFuture中树立新的未来,并要求小部件自行重建。重建FutureBuilder时,它将求值myFuture而不是再次调用http。