「编程笔记」Dart中重新加载FutureBuilder的一种方法

在实战过程中,我们常常遇到需要刷新界面的需求,比如搜索时出现了网络错误,我们为用户提供一个Retry按钮,用户点击后,我们希望整个FutureBuilder重新加载一下,比如下图:

本页面通过一个FutureBuilder加载搜索结果,同时遇到网络错误时显示以上界面,代码的大致结构如下:

Widget build(BuildContext context) {
Widget build(BuildContext context) {
  return FutureBuilder(

    future: getSearchResult(),
    builder: (context, snapshot) {
      // Show user the data
      if (snapshot.hasData) {
        return showDataPage();
      } else if (snapshot.hasError) {
        if (isNetworkError(snapshot.error)) {
          return NetworkErrorPage();
        } else {
          return UnknownErrorPage();
        }
      }
      return LoadingPage();
    },
  );
}

这时,假设我们的NetworkErrorPage的位置需要添加一个按钮,实现FutureBuilder重新刷新,一种简单的方法是直接调用该FutureBuilder所在界面的setState()方法,每当FutureBuilder的父WidgetsetState()方法被调用,都会使得FutureBuilder重新获取异步数据,代码大致如下:

Widget build(BuildContext context) {
  return FutureBuilder(
    builder: (context, snapshot) {
      // Show user the data
      if (snapshot.hasData) {
        return showDataPage();
      } else if (snapshot.hasError) {
        if (isNetworkError(snapshot.error)) {
          return ElevatedButton(
            onPressed: () {
              setState(() {});
            },
            child: Text('Try Again'),
          );
        } else {
          return UnknownErrorPage();
        }
      }
      return LoadingPage();
    },
  );
}

但如果我们按照上述结构实现刷新的工作,我们会发现,虽然在我们点击按钮之后,刷新的工作有在进行,但是页面并不会在点击Try Again按钮后重新回到LoadingPage界面,而是等到加载好之后直接更新界面为showDataPage或者Error的相关界面,这是因为snapshot的hasDatahasError变量仅仅在每次future任务完成后才会刷新。

如果我们想实现点击Try Again按钮之后实时回到LoadingPage界面的话,可以使用snapshot.connectionState进行判断,具体代码如下:

FutureBuilder(
    future: _future,
    builder: (context, snapshot) {
      if (snapshot.connectionState != ConnectionState.done) {
        return _buildLoader();
      }
      if (snapshot.hasError) {
        return _buildError();
      }
      if (snapshot.hasData) {
        return _buildDataView();
      }     
      return _buildNoData();
});

通过以上方法,即可实现点击按钮后立即回到加载界面,直到下一次加载完成之后再次更新界面的效果。