编辑:Minimal reproducible example。请查看main.dart
中的refresh-Method。
我正在使用FutureBuilder
来显示网络请求的结果。我在initstate
中调用提取方法(如建议的here):
Future<List<CheckIn>> futureCheckIn;
@override
void initState() {
super.initState();
_eventArg = Provider.of<EventArg>(context, listen: false);
_helper = ApiHelper(context);
futureCheckIn = _helper.fetchCheckIns(_eventArg.getEvent().id.toString());
}
我现在想使用RefreshIndicator
来允许用户刷新屏幕。
在我的网络请求以异常结束(例如404)之前,这非常有效。通常,该异常会被FutureBuilder
捕获,但是在执行RefreshIndicator
中的请求后,该异常将无法处理...
这是我的代码:
RefreshIndicator buildResult(List<CheckIn> checkIns, BuildContext context) {
return RefreshIndicator(
key: _refreshKey,
onRefresh: () async {
setState(() {});
futureCheckIn =
_helper.fetchCheckIns(_eventArg.getEvent().id.toString()); // this could end with an exception
},
child: Container(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
child: Column(
children: [
Container(
margin: EdgeInsets.all(10),
child: Text(
constants.CHECK_IN_SCREEN_DESCRIPTION,
style: TextStyle(fontSize: 16),
textAlign: TextAlign.justify,
),
),
ListView(
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: checkIns.map((el) {
return Card(
elevation: 4,
child: ListTile(
title: Text(el.name),
onTap: () async {
...
},
trailing: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.arrow_forward_ios,
color: Colors.black,
)
],
),
),
);
}).toList(),
)
],
),
),
),
);
}
如何将RefreshIndicator
与FutureBuilder
一起正确使用?
编辑@Shri Hari:抛出此异常
class AppException implements Exception {
final _message;
final _prefix;
AppException([this._message, this._prefix]);
String toString() {
return "$_prefix$_message";
}
}
class NotFoundException extends AppException {
NotFoundException([String message]) : super(message, "Data not found: ");
}
编辑@Mhark Batoctoy:是的,它是FutureBuilder
的一部分:
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: futureCheckIn,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<CheckIn> checkIns = snapshot.data;
return buildResult(checkIns, context); // RefreshIndicator is nested in here
} else if (snapshot.hasError) {
// Error handling
...
}
// Spinner während der Datenabfrage
return Center(
child: CircularProgressIndicator(),
);
},
);
很不幸地将onRefresh
-方法从更改为
onRefresh: () async {
setState(() {});
futureCheckIn =
_helper.fetchCheckIns(_eventArg.getEvent().id.toString()); // this could end with an exception
},
到
onRefresh: () async {
setState(() {});
return futureCheckIn =
_helper.fetchCheckIns(_eventArg.getEvent().id.toString()); // this could end with an exception
},
或
onRefresh: () async {
setState(() {});
return _helper.fetchCheckIns(_eventArg.getEvent().id.toString()); // this could end with an exception
},
不会更改错误...
答案 0 :(得分:2)
不确定这是否是最佳答案,但我遇到了同样的问题,必须继续前进。所以,这就是我学到的和做的。
RefreshIndicator
不喜欢例外。即使在将它们移到 try / catch
或 onError
下并成功消费异常之后,RefreshIndicator
仍然为未处理的异常而哭泣(有点奇怪,但我将不得不对其进行更多调查)。
我所做的是确保我的 API 调用不会引发任何异常。这意味着,API 调用本身(在本例中为 fetchCheckIns()
函数调用)捕获所有类型的已知/未知异常 [ catch (e)
] 并在您从 API 返回的响应对象中设置一个标志(在本例中为 fetchCheckIns()
的返回类型对象)。
现在,在您的 FutureBuilder
中,当您调用 buildResult(checkIns, context)
时,检查 snapshot.data
并查找任何失败标志。如果失败,请以不同的方式渲染屏幕。即:
if (snapshot.hasData) {
if (snapshot.data.error == true) {
return ...; // Render error message
} else {
return buildResult(snapshot.data, context);
}
}
这也意味着,您可能无法返回对象列表,并且可能必须将其包装在包含对象列表的单个对象中。
意味着,您的 CheckIn
对象可能被类似
class AllCheckIn {
List<CheckIn> checkIns;
bool error;
String errorMsg;
}
或者,您还可以根据您在 API 调用中收到和捕获的异常添加更多错误消息说明,并在您的 FutureBuilder
中使用它。
希望对您有所帮助。
答案 1 :(得分:0)
_helper.fetchCheckIns(_eventArg.getEvent().id.toString());
它返回一个Future。您需要一个data
或一个error
。您可以在async await
块内使用try catch finally
,也可以使用Future.then() / Future.catchError / Future.whenComplete()
。
示例:
onRefresh: () async {
try {
//You can use the await keyword here.
return futureCheckIn =
await _helper.fetchCheckIns(_eventArg.getEvent().id.toString());
}catch (err){
//You can display the error here using a snackbar.
}finally {
//This executes whether there is an error or not.
}
},