首页 > 解决方案 > Flutter - 在 FutureBuilder 中使用 RefreshIndicator 拉动刷新

问题描述

编辑:最小的可重现示例。请查看 中的刷新方法main.dart

我正在使用 aFutureBuilder来显示网络请求的结果。我调用我的 fetch 方法initstate(就像这里建议的那样):

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());
}

我现在想使用 aRefreshIndicator来允许用户刷新屏幕。在我的网络请求以异常结束(例如 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正确使用 with 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 Ba​​toctoy:是的,它是以下内容的一部分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-Method 从

 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
  },

不改变错误...

标签: flutterdartnetworkingfuturetask

解决方案


不确定这是否是最好的答案,但我遇到了同样的问题,必须继续前进。所以,这就是我学到和做到的。

RefreshIndicator不喜欢例外。即使在将它们移到try / catchor下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.

希望这会有所帮助。


推荐阅读