firebase - Flutter Stean builder运行initialay并显示错误在null上调用了getter'length'。但是在手势检测器单击后它运行正确
问题描述
1.这是我需要运行的第一页此代码最初运行并给出“长度”被调用为空。接收器:空尝试调用:长度类型错误,但单击手势后它运行完美我需要在手势检测器调用之前运行此代码我尝试没有手势检测器但它不起作用。
class ProductPage extends StatefulWidget {
@override
_ProductPageState createState() => _ProductPageState();
}
class _ProductPageState extends State<ProductPage> {
String id=' RN62p5KZAtk48mGL2n66';
int selectedIndex = 0;
String district;
bool loading = false;
_ProductPageState();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 30.0,),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: SizedBox(
height: 25,
child:StreamBuilder<List<CategoryModel>>(
stream: DatabaseService().getCategories(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => buildCategory(
index,
snapshot.data[index].categoryName,
snapshot.data[index].id
)
);
},
),
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('district').snapshots(),
builder: (context, snapshot) {
return Container(
padding: EdgeInsets.only(bottom: 16.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.fromLTRB(12.0, 10.0, 10.0, 10.0),
child: Text(
"District",
),
)),
new Expanded(
flex: 4,
child: DropdownButton(
value: district,
isDense: true,
onChanged: (valueSelectedByUser) {
setState(() {
this.district = valueSelectedByUser;
});
print(district);
},
hint: Text('Sort By District'),
items: snapshot.data.docs
.map((DocumentSnapshot document) {
return DropdownMenuItem<String>(
value: document.data()['Name'],
child: Text(document.data()['Name'] ),
);
}).toList(),
),
),
],
),
);
}),
district == null ? Expanded(
flex: 1,
child: StreamBuilder<List<SubCategoryModel>>(
stream:DatabaseService().getSubCategories(id),
builder: (context,snapshot){
if(!snapshot.hasData){
return Center(
child: CircularProgressIndicator(),
);
}else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return PostContainer(
id: snapshot.data[index].listId,
likes: snapshot.data[index].likes,
views: snapshot.data[index].views,
imageUrl: snapshot.data[index].imageUrl,
longitude: snapshot.data[index].longitude,
latitude: snapshot.data[index].latitude,
providerName: snapshot.data[index].providerName,
providerTel: snapshot.data[index].providerTel,
units: snapshot.data[index].units,
description: snapshot.data[index].description,
unitPrice: snapshot.data[index].unitPrice,
name: snapshot.data[index].name,
date: snapshot.data[index].date,
providerId: snapshot.data[index].providerId,
categoryId: snapshot.data[index].categoryId,
providerImage: snapshot.data[index].providerImage,
district: snapshot.data[index].district,
address: snapshot.data[index].address,
);
}
);
}
},
),
):
Expanded(
flex: 1,
child: StreamBuilder<List<SubCategoryModel>>(
stream: DatabaseService().getSortedSubCategories(id, district),
builder: (context,snapshot){
if(!snapshot.hasData){
return Center(
child: CircularProgressIndicator(),
);
}else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return PostContainer(
id: snapshot.data[index].listId,
likes: snapshot.data[index].likes,
views: snapshot.data[index].views,
imageUrl: snapshot.data[index].imageUrl,
longitude: snapshot.data[index].longitude,
latitude: snapshot.data[index].latitude,
providerName: snapshot.data[index].providerName,
providerTel: snapshot.data[index].providerTel,
units: snapshot.data[index].units,
description: snapshot.data[index].description,
unitPrice: snapshot.data[index].unitPrice,
name: snapshot.data[index].name,
date: snapshot.data[index].date,
providerId: snapshot.data[index].providerId,
categoryId: snapshot.data[index].categoryId,
providerImage: snapshot.data[index]
.providerImage,
district: snapshot.data[index].district,
address: snapshot.data[index].address,
);
}
);
}
},
),
),
],
)
);
}
Widget buildCategory(int index,String categoryName,String catId) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
id= catId;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
categoryName,
style: TextStyle(
fontWeight: FontWeight.bold,
color: selectedIndex == index ? Color(0xFF535353) : Color(0xFF535353),
),
),
Container(
margin: EdgeInsets.only(top: 20 / 4), //top padding 5
height: 2,
width: 30,
color: selectedIndex == index ? Colors.black : Colors.transparent,
)
],
),
),
);
}
Future<void> _shoeerror() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Thank you For Join with Us !'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Row(
children: [
Text('Select the Category to proceed '),
],
)
],
),
),
actions: <Widget>[
TextButton(
child: Text('OK'),
onPressed: () {
setState(() {
id=' RN62p5KZAtk48mGL2n66';
});
},
),
],
);
},
);
}
}
2.这是数据库调用函数
Stream<List<SubCategoryModel>> getSubCategories(docId) {
return _db.collection('categories').doc(docId).collection('subCategories').snapshots().map((snapshot) =>
snapshot.docs.map((doc) => SubCategoryModel.fromJson(doc.data())).toList());
}
解决方案
我怀疑这是在每个构建上执行的,都会产生副作用......也许将流重新创建回其初始状态:
stream: DatabaseService().getCategories()
对于期望未来或流的“构建器”小部件,您需要在 build() 方法之外创建它们正在观察的值......也许在 initState 或我最喜欢的 Riverpod 提供程序中。
此外,您似乎没有任何基于 snapshot.data 的非空值的条件,所以它会因为 .length 而爆炸。这是预期的行为。:)
推荐阅读
- java - 带有 NTLM 的 Java HTTPClient 4.5,无法获得 NTLMv2 身份验证
- perl - 我的模拟结果不直观
- firebase - 在构建服务器上测试 Firebase Cloud Function 时出现 admin.credential.applicationDefault() 错误:无法刷新访问令牌
- regex - 正则表达式过滤文本后的数字
- java - 已安装 Java 但未能要求包“XLConnect”
- python - 替换数组中值的最快方法
- javascript - Swagger..无法呈现此定义 提供的定义未指定有效的版本字段
- javascript - RxJS 中的自我修复错误处理
- javascript - DraftJs:如何插入其中包含链接的 html?
- python - 熊猫在某些字符之前和之后删除文本