为什么 snapshot.data.length 会出错?

Why is there an error with snapshot.data.length?

我正在尝试解析来自 API 的数据。为此,我使用 FutureBuilder 在 ListView 中列出所有已解析的数据。

我已经对 snapshot.data 的无效性进行了检查,但我在段 snapshot.data.length 中不断收到此错误,它说 The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').

我在 snapshot.data[i] 部分有一个类似的错误,它说 The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').

这是我的代码的相同部分:

 body: Container(
        child: FutureBuilder(
          future: getData('hello'),
          builder: (context, snapshot) {
            if (snapshot.data == null) {
              return Container(
                child: Text("Loading"),
              );
            }else{
              return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, i) {
                    return ListTile(
                      title: snapshot.data[i].partOfSpeech,
                    );
                  });
            }
          },
        ),
      ),

这里是 getData(String s):

Future<List> getData(String s) async {
  var response = await http
      .get(Uri.https('api.dictionaryapi.dev', 'api/v2/entries/en_US/' + s));
  var jsonData = jsonDecode(response.body)[0];

  List<Data> data = [];

  for (var x in jsonData["meanings"]) {
    String definition = x["definitions"][0]["definition"];
    Data d = Data(x["partOfSpeech"], definition);
    data.add(d);
  }

  return data;
}

由于您正在检查 snapshot.data 不为空,因此您可以执行以下操作来修复它。

 body: Container(
        child: FutureBuilder(
          future: getData('hello'),
          builder: (context, snapshot) {
            if (snapshot.data == null) {
              return Container(
                child: Text("Loading"),
              );
            } else{
              return ListView.builder(
                  itemCount: snapshot.data!.length,
                  itemBuilder: (context, i) {
                    return ListTile(
                      title: snapshot.data[i]!.partOfSpeech,
                    );
                  });
            }
          },
        ),
      ),

你要看的是getData('hello')

的结果

显然,它不 return 长度为 属性 的东西。

继续 , 我找到了解决问题的办法。显然 getData 没有按预期返回列表。相反,它返回一个对象。

类型转换 要列出的对象解决了问题。

这是更正后的代码:

body: Container(
        child: FutureBuilder(
          future: getData('hello'),
          builder: (context, snapshot) {
            if (snapshot.data == null) {
              return Container(
                child: Text("Loading"),
              );
            }else{
              //typecasting Object to List
              var data = (snapshot.data as List<Data>).toList();
              return ListView.builder(
                  itemCount: data.length,
                  itemBuilder: (context, i) {
                    return ListTile(
                      title: data[i].partOfSpeech,
                    );
                  });
            }
          },
        ),
      ),

如果您使用的是新版本的 flutter(2.2.0 或更高版本)。首先尝试向目标添加空检查('!')。因为 null 安全功能。

 body: Container(
    child: FutureBuilder(
      future: getData('hello'),
      builder: (context, snapshot) {
        if (snapshot.data == null) {
          return Container(
            child: Text("Loading"),
          );
        }else{
          return ListView.builder(
              itemCount: snapshot.data!.length,
              itemBuilder: (context, i) {
                return ListTile(
                  title: snapshot.data[i].partOfSpeech,
                );
              });
        }
      },
    ),
  ),

然后尝试将 FutureBuilder 类型指定为数据类型列表

 body: Container(
    child: FutureBuilder<List<Data>>(
      future: getData('hello'),
      builder: (context, snapshot) {
        if (snapshot.data == null) {
          return Container(
            child: Text("Loading"),
          );
        }else{
          return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (context, i) {
                return ListTile(
                  title: snapshot.data[i].partOfSpeech,
                );
              });
        }
      },
    ),
  ),

在构建器参数中将 'AsyncSnapshot' 放在快照之前。

builder: (context, AsyncSnapshot snapshot)