You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter应用跳转地址页面时冻结无响应,请求技术协助

解决Flutter Firestore地址列表页面冻结问题

问题描述

开发连接Firebase Firestore的Flutter应用时,其他页面路由正常,但跳转至地址列表页面时应用完全冻结,控制台无错误输出,无法进行热重载/热重启,只能终止进程后重新运行。注释StreamBuilder内的代码后,页面可正常跳转,确认问题源于该组件逻辑。

代码问题分析

  1. 嵌套ListView引发无限布局计算
    外层ListView.builder内部返回包含另一个ListView.builder的Column,且外层ListView未限制高度,结合Expanded会导致Flutter布局系统陷入无限循环计算,直接触发应用冻结。

  2. 低效的集合遍历逻辑
    当前监听整个customers集合快照,再通过ListView.builder遍历所有文档匹配当前用户ID,不仅浪费资源,还会在每个文档项中重复构建完整地址UI,加剧性能消耗。

  3. 缺失异步状态处理
    未处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:35:18