So, I am learning to use the FutureBuilder class in Flutter. My code works, but I wonder if I could improve the way I access the data from the snapshot.
My FutureBuilder is like that:
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: FutureBuilder<List<ListCard>>(
future: items,
builder: (context, snapshot) {
return RefreshIndicator(
onRefresh: _pullRefresh,
child: _listView(snapshot),
);
},
),
),
);
}
items is a class property of type Future<List<ListCard>>. _listView is the method where I work on the snapshot. There are 2 errors in this code:
Widget _listView(AsyncSnapshot<List<ListCard>> snapshot) {
if (snapshot.data != null) {
return ListView.builder(
itemCount: snapshot.data.length, // Error when accessing the length property
itemBuilder: (context, index) {
return snapshot.data[index]; // Error when accessing the index
},
);
} else {
return const Center(child: CircularProgressIndicator());
}
}
The two errors are actually the same. They say:
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 ('!').dart(unchecked_use_of_nullable_value)
I understand that snapshot.data is of type List<ListCard>?, therefore its value can either be null or a list of type List<ListCard>. In case the value is null, Flutter will display the CircularProcessIndicator. If it's not null, then the ListView.builder widget will be returned. If we reach that point, snapshot.data is always a list (it's been tested in the if statement) and it should therefore have a length property.
I also tried:
Widget _listView(AsyncSnapshot<List<ListCard>> snapshot) {
if (snapshot.data is List<ListCard>) {
//...
}
but it gives exactly the same error. Same story with:
Widget _listView(AsyncSnapshot<List<ListCard>> snapshot) {
if (snapshot.hasData) {
//...
}
However I can get rid of these errors by adding the ! operator:
//...
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return snapshot.data![index];
},
//...
I could also do a type assertion such as List<ListCard> data = snapshot.data as List<ListCard>; but I don't want to go that way.
Is it possible to make this work without using the ! operator?
Thanks!
I presume the problem you are facing is because snapshot can not be promoted to non nullable.
In your case you will have to go using "!" after a null-check.
Remember
Type promotion is only applicable to local variables... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. Cf. dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
For further information on this topic see this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With