通过 try/catch 收到失败后 FutureBuilder 不会更新
FutureBuilder doesn't update after failure recieved via try/catch
我有 FutureBuilder,它接受来自 HTTP GET 请求的未来。 Future 对象在点击提交按钮时初始化,这也是基于 isInEditMode bool。
- 我第一次点击“提交”时,连接状态从 none 变为预期的等待完成。
- 假设未来从 Get 请求中捕获错误,我可以将其优雅地放入 catch 块中,我得到 connectionState.done 这很好。
- 现在问题出现在第二次点击提交按钮时,它不会将 future 的连接状态更新为等待,反过来,构建器也不会相应地显示在屏幕上。
- 我已经检查过,每次我点击“提交”按钮时,都会从 Get 请求中检索到全新的未来对象,但它不会反映在 FutureBuilder 中。如何让FutureBuilder知道Future对象是renewed/changed,适配新的??
class AddEditProductSoScreen extends StatefulWidget {
static const routeName = '/add-edit-product';
@override
_AddEditProductSoScreenState createState() => _AddEditProductSoScreenState();
}
class _AddEditProductSoScreenState extends State<AddEditProductSoScreen> {
var isEditMode = false;
final _formKey = GlobalKey<FormState>();
ProductFormModel _formProduct;
Future<Response> futureOfSubmit;
bool isLoadingVisible = false;
@override
Widget build(BuildContext context) {
final productsProvider =
Provider.of<ProductsProvider>(context, listen: false);
Product product = ModalRoute.of(context).settings.arguments;
if (product != null) {
isEditMode = true;
_formProduct = ProductFormModel.copyFromProduct(product);
} else {
_formProduct = ProductFormModel.init();
}
return Scaffold(
bottomNavigationBar: Container(
height: 50,
child: Material(
color: Theme.of(context).accentColor,
child: InkWell(
onTap: isLoadingVisible
? null
: () {
if (isEditMode) {
futureOfSubmit =
productsProvider.editProduct(_formProduct);
} else {
futureOfSubmit =
productsProvider.addProduct(_formProduct);
}
isLoadingVisible = true;
futureOfSubmit.then((value) {
//Navigator.of(context).pop();
}).catchError((error) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('An error occurred!'),
content: Text('Something went wrong.'),
actions: [
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Okay'))
],
));
}).whenComplete(() {
setState(() {
isLoadingVisible = false;
});
});
},
child: FutureBuilder(
future: futureOfSubmit,
builder: (context, AsyncSnapshot<Response> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Align(
alignment: Alignment.center,
child: Container(
height: 30,
width: 30,
child: CircularProgressIndicator(
backgroundColor: Colors.white,
)),
);
} else {
return Container(
padding: EdgeInsets.all(10),
width: double.infinity,
child: Text(
'SUBMIT',
style: TextStyle(color: Colors.white, fontSize: 20),
textAlign: TextAlign.center,
),
);
}
},
),
),
),
),
);
}
}
任何帮助将不胜感激,谢谢!
编辑:这里是 productProvider class 的 addProduct 方法,它返回 future 对象并抛出异常..
Future<Response> addProduct(ProductFormModel product) async {
const url = '................';
try {
Response response = await http.post(url,
body: json.encode({
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavorite': product.isFav
}));
Map respMap = json.decode(response.body);
product.id = respMap['name'];
_items.add(product.toProduct());
notifyListeners();
return response;
} on Exception catch (error) {
print("error is :: " + error.toString());
throw Exception('Something went wrong!!');
}
}
要通知框架,您的小部件的状态已更改,您可以使用 StatefulWidget
的 setState
方法。
所以这个:
futureOfSubmit = productsProvider.editProduct(_formProduct);
应该是:
setState(() { futureOfSubmit = productsProvider.editProduct(_formProduct); });
其他人也是如此。
使用
setState((){});
通知框架状态已更改。
在你的 If else 块中使用 setState
setState(() {
futureOfSubmit = productsProvider.editProduct(_formProduct);
});
我有 FutureBuilder,它接受来自 HTTP GET 请求的未来。 Future 对象在点击提交按钮时初始化,这也是基于 isInEditMode bool。
- 我第一次点击“提交”时,连接状态从 none 变为预期的等待完成。
- 假设未来从 Get 请求中捕获错误,我可以将其优雅地放入 catch 块中,我得到 connectionState.done 这很好。
- 现在问题出现在第二次点击提交按钮时,它不会将 future 的连接状态更新为等待,反过来,构建器也不会相应地显示在屏幕上。
- 我已经检查过,每次我点击“提交”按钮时,都会从 Get 请求中检索到全新的未来对象,但它不会反映在 FutureBuilder 中。如何让FutureBuilder知道Future对象是renewed/changed,适配新的??
class AddEditProductSoScreen extends StatefulWidget {
static const routeName = '/add-edit-product';
@override
_AddEditProductSoScreenState createState() => _AddEditProductSoScreenState();
}
class _AddEditProductSoScreenState extends State<AddEditProductSoScreen> {
var isEditMode = false;
final _formKey = GlobalKey<FormState>();
ProductFormModel _formProduct;
Future<Response> futureOfSubmit;
bool isLoadingVisible = false;
@override
Widget build(BuildContext context) {
final productsProvider =
Provider.of<ProductsProvider>(context, listen: false);
Product product = ModalRoute.of(context).settings.arguments;
if (product != null) {
isEditMode = true;
_formProduct = ProductFormModel.copyFromProduct(product);
} else {
_formProduct = ProductFormModel.init();
}
return Scaffold(
bottomNavigationBar: Container(
height: 50,
child: Material(
color: Theme.of(context).accentColor,
child: InkWell(
onTap: isLoadingVisible
? null
: () {
if (isEditMode) {
futureOfSubmit =
productsProvider.editProduct(_formProduct);
} else {
futureOfSubmit =
productsProvider.addProduct(_formProduct);
}
isLoadingVisible = true;
futureOfSubmit.then((value) {
//Navigator.of(context).pop();
}).catchError((error) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('An error occurred!'),
content: Text('Something went wrong.'),
actions: [
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Okay'))
],
));
}).whenComplete(() {
setState(() {
isLoadingVisible = false;
});
});
},
child: FutureBuilder(
future: futureOfSubmit,
builder: (context, AsyncSnapshot<Response> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Align(
alignment: Alignment.center,
child: Container(
height: 30,
width: 30,
child: CircularProgressIndicator(
backgroundColor: Colors.white,
)),
);
} else {
return Container(
padding: EdgeInsets.all(10),
width: double.infinity,
child: Text(
'SUBMIT',
style: TextStyle(color: Colors.white, fontSize: 20),
textAlign: TextAlign.center,
),
);
}
},
),
),
),
),
);
}
}
任何帮助将不胜感激,谢谢!
编辑:这里是 productProvider class 的 addProduct 方法,它返回 future 对象并抛出异常..
Future<Response> addProduct(ProductFormModel product) async {
const url = '................';
try {
Response response = await http.post(url,
body: json.encode({
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavorite': product.isFav
}));
Map respMap = json.decode(response.body);
product.id = respMap['name'];
_items.add(product.toProduct());
notifyListeners();
return response;
} on Exception catch (error) {
print("error is :: " + error.toString());
throw Exception('Something went wrong!!');
}
}
要通知框架,您的小部件的状态已更改,您可以使用 StatefulWidget
的 setState
方法。
所以这个:
futureOfSubmit = productsProvider.editProduct(_formProduct);
应该是:
setState(() { futureOfSubmit = productsProvider.editProduct(_formProduct); });
其他人也是如此。
使用
setState((){});
通知框架状态已更改。
在你的 If else 块中使用 setState
setState(() {
futureOfSubmit = productsProvider.editProduct(_formProduct);
});