Flutter应用跳转地址页面时冻结无响应,请求技术协助
解决Flutter Firestore地址列表页面冻结问题
问题描述
开发连接Firebase Firestore的Flutter应用时,其他页面路由正常,但跳转至地址列表页面时应用完全冻结,控制台无错误输出,无法进行热重载/热重启,只能终止进程后重新运行。注释StreamBuilder内的代码后,页面可正常跳转,确认问题源于该组件逻辑。
代码问题分析
嵌套ListView引发无限布局计算
外层ListView.builder内部返回包含另一个ListView.builder的Column,且外层ListView未限制高度,结合Expanded会导致Flutter布局系统陷入无限循环计算,直接触发应用冻结。低效的集合遍历逻辑
当前监听整个customers集合快照,再通过ListView.builder遍历所有文档匹配当前用户ID,不仅浪费资源,还会在每个文档项中重复构建完整地址UI,加剧性能消耗。缺失异步状态处理
未处理snapshot.connectionState的加载状态,无加载指示器;逻辑分支不严谨,易出现空指针或异常。
解决方案
步骤1:优化Firestore查询
直接通过where条件过滤当前用户文档,减少数据传输量:
stream: FirebaseFirestore.instance .collection('customers') .where('uid', isEqualTo: currUserId) .snapshots(),
步骤2:重构布局,避免嵌套ListView冲突
移除外层ListView.builder,改用SingleChildScrollView包裹内容,内层ListView添加shrinkWrap: true和固定高度:
builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return const Center(child: Text('加载出错')); } if (!snapshot.hasData || snapshot.data!.docs.isEmpty) { return const Center(child: Text('暂无地址数据')); } final userDoc = snapshot.data!.docs.first; firestoreAddresses = List.from(userDoc.get('addresses')); return Expanded( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 2.h), Padding( padding: EdgeInsets.symmetric(horizontal: 5.w), child: Text( "Current Address", style: globalTextStyle.copyWith( color: black, fontSize: 4.w, fontWeight: FontWeight.bold, ), ), ), SizedBox(height: 1.h), AddressCard( onTap: () {}, isDefault: true, name: addressTiles[1].name, address: "${currentAddress.houseNum}, ${currentAddress.village}, ${currentAddress.district}, ${currentAddress.state}, ${currentAddress.pinCode}", onEditTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => EditAddressScreen( address: addressTiles[1], addressIndex: 100, isDefault: true, ), ), ); }, onDefaultTap: () {}, onRemoveTap: () {}, ), SizedBox(height: 0.5.h), Padding( padding: EdgeInsets.symmetric(horizontal: 5.w), child: Container( width: 90.w, height: 0.5, color: grey, ), ), SizedBox(height: 1.5.h), Padding( padding: EdgeInsets.symmetric(horizontal: 5.w), child: Text( "My Addresses", style: globalTextStyle.copyWith( color: black, fontSize: 4.w, fontWeight: FontWeight.bold, ), ), ), SizedBox(height: 1.h), SizedBox( height: 40.5.h, child: ListView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), itemCount: firestoreAddresses.length, itemBuilder: (context, index) { return AddressCard( onTap: () {}, isDefault: firestoreAddresses[index]['isDefault'], name: firestoreAddresses[index]['name'], address: "${firestoreAddresses[index]['houseNum']}, ${firestoreAddresses[index]['village']}, ${firestoreAddresses[index]['district']}, ${firestoreAddresses[index]['state']}, ${firestoreAddresses[index]['pinCode']}", onEditTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => EditAddressScreen( address: firestoreAddresses[index], addressIndex: index, isDefault: firestoreAddresses[index]['isDefault'], ), ), ); }, onDefaultTap: () {}, onRemoveTap: () {}, ); }, ), ), ], ), ), ); }
步骤3:初始化状态变量
在State类中初始化firestoreAddresses,避免未初始化导致的异常:
class _AddressListScreenState extends State<AddressListScreen> { final String? currUserId = FirebaseAuth.instance.currentUser?.uid; List<dynamic> firestoreAddresses = []; @override Widget build(BuildContext context) { // 其余代码 } }
内容的提问来源于stack exchange,提问作者Ayan Dasgupta
相关产品推荐
相关产品推荐

