Flutter-FutureBuilder不等待将来完成

时间:2019-05-22 05:15:20

标签: android flutter

我正在使用API​​调用来获取数据并显示在ListView中。

这是将来的构建器类:

Widget futureBuilder() {
    return FutureBuilder<List<Project>>(
      future: _getProjects(),
      builder: (context, snapshot) {
        debugPrint('Builder');
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
          default:
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            else
              return listWidget(snapshot);
        }
      },
    );
  }
}

问题是,甚至在_getProjects()返回结果之前,也会调用debugPrint('Builder'),因此快照在null中传递为ListView窗口小部件。

这是_getProjects()类:

Future<List<Project>> _getProjects() async {
    List<Project> projects = [];
    String getProjects = "https://api.myjson.com/bins/1g3xpe";
    var response = await http.get(getProjects);
    Iterable list = json.decode(response.body);
    projects = list.map((model) => Project.fromJson(model)).toList();
    debugPrint('Size ' + projects.length.toString());
    return projects;
  }

这是完整的代码:

class Projects extends StatefulWidget {
  @override
  ProjectState createState() => new ProjectState();
}

class ProjectState extends State {

   Future<List<Project>> _getProjects() async {
    List<Project> projects = [];
    String getProjects = "https://api.myjson.com/bins/1g3xpe";
    var response = await http.get(getProjects);
    Iterable list = json.decode(response.body);
    projects = list.map((model) => Project.fromJson(model)).toList();
    debugPrint('Size ' + projects.length.toString());
    return projects;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      primary: true,
      appBar: EmptyAppBar(),
      body: Column(
        children: <Widget>[
          headerWidget(),
          futureBuilder()
        ],
      ),
    );
  }

  Widget futureBuilder() {
    return FutureBuilder<List<Project>>(
      future: _getProjects(),
      builder: (context, snapshot) {
        debugPrint('Builder');
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
          default:
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            else
              return listWidget(snapshot);
        }
      },
    );
  }
}



Widget headerWidget() {
  return Container(
    padding: EdgeInsets.all(16.0),
    color: Colors.blueAccent,
    child: Container(
        decoration: ShapeDecoration(
            color: Colors.white,
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(25.0)),
                side: BorderSide(color: Colors.white))),
        child: Row(
          children: <Widget>[
            Padding(padding: EdgeInsets.only(left: 12)),
            Icon(Icons.arrow_back, color: Colors.black54),
            Padding(padding: EdgeInsets.only(left: 12)),
            Flexible(
              fit: FlexFit.loose,
              child: searchBar(),
            ),
            Icon(
              Icons.search,
              color: Colors.black54,
            ),
            Padding(padding: EdgeInsets.only(right: 12)),
          ],
        )),
  );
}

Widget searchBar() {
  return Container(
    height: 52,
    alignment: Alignment.centerLeft,
    padding: EdgeInsets.only(left: 12, right: 12),
    child: TextField(
      decoration: new InputDecoration.collapsed(
        border: InputBorder.none,
        filled: false,
        hasFloatingPlaceholder: false,
        hintText: 'Search here',
        hintStyle: TextStyle(color: Colors.black54),
      ),
    ),
  );
}

Widget listWidget(AsyncSnapshot<List<Project>> snapshot) {
  return Scaffold(
      body: ListView.builder(
          itemBuilder: (BuildContext context, int index) {
            listItem(snapshot.data[index]);
          },
          itemCount: snapshot.data.length));
}

Widget listItem(Project project) {
  return Card(
    elevation: 6.0,
    child: Column(
      children: <Widget>[Text('Project ID'), Text('Project Name')],
    ),
  );
}

class EmptyAppBar extends StatelessWidget implements PreferredSizeWidget {
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  @override
  Size get preferredSize => Size(0.0, 0.0);
}

更新: 我对FutureBuilder进行了一些更改:

Widget futureBuilder() {
    return FutureBuilder<List<Project>>(
      future: _getProjects(),
      builder: (context, snapshot) {
        debugPrint('Builder');
        switch (snapshot.connectionState) {
          case ConnectionState.done:
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            else
              return listWidget(snapshot);
            break;

          default:
            debugPrint("Snapshot " + snapshot.toString());
        }
      },
    );
  }

我现在收到此错误:

I/flutter ( 4054): _FutureBuilderState<List<Project>>#67dc4):
I/flutter ( 4054): A build function returned null.
I/flutter ( 4054): The offending widget is: FutureBuilder<List<Project>>
I/flutter ( 4054): Build functions must never return null. To return an empty space that causes the building widget to
I/flutter ( 4054): fill available room, return "new Container()". To return an empty space that takes as little room as
I/flutter ( 4054): possible, return "new Container(width: 0.0, height: 0.0)".

默认情况下,SnapShot返回此快照AsyncSnapshot>(ConnectionState.waiting,null,null)

2 个答案:

答案 0 :(得分:1)

  

I / flutter(4054):构建函数返回null。

无论什么情况,您始终需要从构建器返回小部件:

Widget futureBuilder() {
        return FutureBuilder<List<Project>>(
          future: _getProjects(),
          builder: (context, snapshot) {
            debugPrint('Builder');
            switch (snapshot.connectionState) {
              case ConnectionState.done:
                if (snapshot.hasError)
                  return new Text('Error: ${snapshot.error}');
                else
                  return listWidget(snapshot);
                break;

              default:
                debugPrint("Snapshot " + snapshot.toString());
              return Container() // also check your listWidget(snapshot) as it may return null.
            }
          },
        );
      }
  

问题是,甚至在调用debugPrint('Builder')之前   _getProjects()返回结果,因此快照在我的ListView窗口小部件中作为null传递。

这是正常现象,例如,如果您有一个漫长的任务(一个请求或一些非常长的计算),则需要显示负载,直到将来“完成”为止。另外,将要执行的内容置于“未来”,这意味着您可以“稍后”执行它,否则,您需要使用 await

答案 1 :(得分:0)

您需要检查AsyncSnapshot(快照)是否返回任何数据。 添加一个PRIM语句,如下所示:

if