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

Stream已发射数据但StreamBuilder未接收数据的排查求助

问题分析与解决方案

核心原因

Stream已经获取到Firestore的数据,但数据解析过程中抛出了未捕获的异常,导致转换后的Stream无法正常传递数据到StreamBuilder,最终snapshot.data为null。

从日志可以看到,流的map操作里已经打印出了The data is Order Placed,说明Firestore查询到了目标数据,但在调用OrderAddressModel.fromJson(document.data())时出现了错误,异常中断了数据传递,使得StreamBuilder接收不到有效数据。

排查与修复步骤

1. 捕获Stream中的错误

先在StreamBuilder里添加错误处理逻辑,确认具体异常信息:

builder: (context, snapshot) {
  debugPrint("Hello there");
  
  // 新增:检查Stream是否抛出错误
  if (snapshot.hasError) {
    debugPrint("Stream异常:${snapshot.error}");
    return Text("加载出错:${snapshot.error}");
  }

  if (snapshot.hasData && snapshot.data?.isNotEmpty == true) {
    debugPrint("I am having data");
    final orderAddressModels = snapshot.data!;
    return ListView.builder(
      itemCount: orderAddressModels.length,
      itemBuilder: (context, index) {
        final orderAddressModel = orderAddressModels[index];
        return ListTile(
          title: Text(orderAddressModel.orderModel?.id ?? ''),
          subtitle: Text(orderAddressModel.addressModel?.fullName ?? ''),
        );
      },
    );
  }
  if (snapshot.connectionState == ConnectionState.waiting) {
    return const ShimmerAddress();
  }

  return NoDataHelper(
      iconData: Icons.shopping_bag_outlined,
      title: "No Orders Yet",
      buttonTitle: "Order Now",
      buttonType: ButtonType.filled,
      onTap: () => {context.pushNamed(Routes.addressAdd)});
},

2. 修正Model解析逻辑

从OrderAddressModel.fromJson的代码来看,有两个高危点:

  • AddressModel.fromJsonString(json['addressModel']):如果Firestore中addressModel字段存储的是Map类型而非JSON字符串,调用fromJsonString会直接抛出异常,应该改为AddressModel.fromJson(json['addressModel'])(前提是AddressModel有对应的fromJson方法)。
  • OrderModel.fromJson(json['orderModel'], json['orderModel']['id']):检查OrderModel的构造函数是否需要两个参数,同时确认Firestore中的orderModel对象是否包含id字段,若字段不存在或类型不匹配,会抛出异常。

另外,建议在解析时添加局部异常捕获,避免单个数据解析失败导致整个流中断:

return data.map((snapshot) => snapshot.docs.map((document) {
      debugPrint("The data is ${document.data()['orderModel']['deliveryStatus']}");
      try {
        return OrderAddressModel.fromJson(document.data());
      } catch (e, stackTrace) {
        debugPrint("单条数据解析失败:$e");
        debugPrint(stackTrace.toString());
        return null; // 跳过错误数据,不影响其他数据
      }
    }).where((item) => item != null).toList() as List<OrderAddressModel>);

3. 避免重复创建Stream

当前代码每次StreamBuilder重建时,都会调用getOrderAddress创建新的Firestore Stream,这会导致重复订阅、数据重复加载甚至异常。建议在Cubit中提前初始化并复用Stream:

class UserCubit extends Cubit<UserState> {
  late final Stream<List<OrderAddressModel>> _orderPlacedStream;

  UserCubit() : super(UserInitial()) {
    // 提前初始化Stream,避免重复创建
    _orderPlacedStream = FirebaseFirestore.instance
        .collection('orders')
        .where('orderModel.deliveryStatus', isEqualTo: "Order Placed")
        .snapshots()
        .map((snapshot) => snapshot.docs.map((document) {
              debugPrint("The data is ${document.data()['orderModel']['deliveryStatus']}");
              try {
                return OrderAddressModel.fromJson(document.data());
              } catch (e) {
                debugPrint("解析错误:$e");
                return null;
              }
            }).where((item) => item != null).toList() as List<OrderAddressModel>);
  }

  // 对外提供已初始化的Stream
  Stream<List<OrderAddressModel>> getOrderPlacedStream() => _orderPlacedStream;
}

然后在StreamBuilder中使用复用的Stream:

stream: BlocProvider.of<UserCubit>(context).getOrderPlacedStream(),

内容的提问来源于stack exchange,提问作者New User

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:59:59