所以,我正在学习使用Flutter
中的FutureBuilder类。我的代码可以工作,但我想知道我是否可以改进从快照访问数据的方式。我的FutureBuilder
是这样的:
@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
是Future<List<ListCard>>
型的一类性质。_listView
是我在快照上工作的方法。这段代码中有两个错误:
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());
}
}
这两个错误实际上是相同的。他们说:
属性'length'不能无条件访问,因为接收者可以是'null'。尝试使访问有条件(使用'?.')或者向目标添加空检查("!").dart (unchecked_use_of_nullable_value)
我知道snapshot.data
是List<ListCard>?
类型的,因此它的值可以是null
或List<ListCard>
类型的列表。如果该值为空,Flutter将显示CircularProcessIndicator
。如果它不为空,那么将返回ListView.builder
小部件。如果我们到达这个点,snapshot.data
总是一个列表(它已经在If语句中测试过了),因此它应该有一个长度属性。
我也试过:
Widget _listView(AsyncSnapshot<List<ListCard>> snapshot) {
if (snapshot.data is List<ListCard>) {
//...
}
,但它给出完全相同的错误。
Widget _listView(AsyncSnapshot<List<ListCard>> snapshot) {
if (snapshot.hasData) {
//...
}
但是,我可以通过添加!
操作符来消除这些错误:
//...
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return snapshot.data![index];
},
//...
我也可以做一个类型断言,如List<ListCard> data = snapshot.data as List<ListCard>;
,但我不想那样做。
不使用!
操作符是否可以使此工作?
谢谢!
我认为你面临的问题是因为snapshot
不能被提升为非空。
"; 记得
类型提升只适用于局部变量…促进实例变量是不可靠的,因为它可能被Getter,它运行一个计算并分别返回一个不同的对象调用它的时间。参考dart-lang/language#1188进行讨论一种类似于类型提升但基于动态的机制检查,并链接到相关讨论
有关此主题的进一步信息,请参阅此回答。
你处理builder
的方式是错误的,试试这个:
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<ListCard> data = snapshot.data ?? [];
return RefreshIndicator(
onRefresh: _pullRefresh,
child: _listView(data),
);
}
}
},
这里我设置data
的默认值,如果它为空,我将传递空列表。