1

I am trying to parse data from an API. For that, I am using FutureBuilder to list all the parsed data in a ListView.

I've performed a check for nullity of snapshot.data but I keep on getting this error in the segment snapshot.data.length, it says, 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 ('!').

I've a similar error in the snapshot.data[i] section, which says 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 ('!').

Here is my code's section of the same:

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

Here's 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;
}
Shourya Shikhar
  • 1,342
  • 1
  • 11
  • 29

5 Answers5

5

In continuation to this answer, I found the solution to my problem. Apparently getData was not returning a List as intended. Instead, it was returning an Object.

Typecasting the Object to List solved the problem.

Here's the corrected code:

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,
                    );
                  });
            }
          },
        ),
      ),
Shourya Shikhar
  • 1,342
  • 1
  • 11
  • 29
5

if u are using a new version of flutter (2.2.0 or above). first try adding a null check to the target ('!'). because of the null safety feature.

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

then try specifying the FutureBuilder type to a List of Data type

 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,
                );
              });
        }
      },
    ),
  ),
2

Put 'AsyncSnapshot' before snapshot in the builder parameter.

builder: (context, AsyncSnapshot snapshot)
Tit
  • 21
  • 1
0

Since you are checking that snapshot.data is not null you can do the following to fix it.

 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,
                    );
                  });
            }
          },
        ),
      ),
quoci
  • 2,940
  • 1
  • 9
  • 21
  • After changing the line to `itemCount: snapshot.data!.length`, a new error is being generated: `The getter 'length' isn't defined for the type 'Object'. Try importing the library that defines 'length', correcting the name to the name of an existing getter, or defining a getter or field named 'length'.` – Shourya Shikhar Jun 29 '21 at 08:13
  • Can you check what type `snapshot.data` is? – quoci Jun 29 '21 at 08:19
  • just checked using `snapshot.data.runtimeType`, got the result as `List` – Shourya Shikhar Jun 29 '21 at 10:05
0

What you need to look at is the result of getData('hello')

Apparently, it does not return something that has a length property.

cenk ebret
  • 687
  • 4
  • 15