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

Flutter无法从Firebase Firestore获取Map类型package数据

问题:无法从Firestore获取package数据

数据模型

data model

相关代码

Services类

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:ilab/services/User.dart';

class Services {
  final _db = FirebaseFirestore.instance.collection('tests');

  // 从快照转换为测试列表
  List<Test> _testsListFromSnapshot(QuerySnapshot snapshot) {
   return snapshot.docs.map((DocumentSnapshot document) {
      Map<String, dynamic> data = document.data() as Map<String, dynamic>;
      return Test(
                details: data['details'] ?? '',
                name: data['name'] ?? '',
                price: data['price'] ?? '',
                type: data['type'] ?? '',
                package: data['package'] ?? '', // 此处存在问题:默认值应为空Map而非空字符串
                indication: data['indication'] ?? '',
                method: data['method'] ?? '',
                general: data['general'] ?? '',
                specimen_type: data['specimen_type'] ?? '',
                time: data['time'] ?? '',
                notes: data['notes'] ?? '',
                preanalytic_precautions: data['preanalytic_precautions'] ?? '',
                ref_rangeUnits: data['ref_rangeUnits'] ?? '',
                add: data['add'] ?? '',
                dateFrom: data['dateFrom'] ?? '',
                dateTo: data['dateTo'] ?? '',
            );
    }).toList();

  }

// 获取测试数据流
  Stream<List<Test>> get Tests {
    return _db.snapshots().map(_testsListFromSnapshot);
  }
}

Test实体类

import 'package:cloud_firestore/cloud_firestore.dart';

class Test{
  final String details;
  final String name;
  final String price;
  final String type;
  final String general ;
  final String preanalytic_precautions ;
  final String indication ;
  final String specimen_type ;
  final String time ;
  final String ref_rangeUnits ;
  final String notes ;
  final String method ;
  final String add;
  final String dateFrom;
  final String dateTo;
  final Map package; // 建议指定类型为Map<String, dynamic>?

  Test({
    this.details,
    this.name,
    this.price,
    this.type,
    this.package,
    this.general,
    this.time,
    this.indication,
    this.method,
    this.notes,
    this.preanalytic_precautions,
    this.ref_rangeUnits,
    this.specimen_type,
    this.add,
    this.dateFrom,
    this.dateTo
  });

  factory Test.fromDocument(DocumentSnapshot doc){
    return Test(
      details: doc['details'],
      name: doc['name'],
      price: doc['price'],
      type: doc['type'],
      method: doc['method'],
      indication: doc['indication'],
      preanalytic_precautions: doc['preanalytic_precautions'],
      specimen_type: doc['specimen_type'],
      general: doc['general'],
      ref_rangeUnits: doc['ref_rangeUnits'],
      time: doc['time'],
      notes: doc['notes'],
      add: doc['add'],
      dateTo: doc['dateTo'],
      dateFrom: doc['dateFrom'],
      package: doc['package'],
    );
  }
}

UI代码

ListView.builder(
  shrinkWrap: true,
  padding: EdgeInsets.all(1.h),
  controller: scrollController,
  scrollDirection: Axis.vertical,
  itemBuilder: (BuildContext context, int index) {
    if (filteredTests != null) {
      return Card(
        child: Padding(
            padding: EdgeInsets.all(5.0),  
            child: _card(index)),
      );
    } else {
      return Center(child: Text('لا توجد بيانات ',style: TextStyle(fontFamily: 'Cairo')));
    }
  },
  itemCount: filteredTests.length,
  itemExtent: 240.0,
)


// 根据数据类型返回不同卡片样式
Widget _card(int index) {
  try {
    Color selectedColour(index) {
      Color c;
      if (index % 4 == 0) c = Colors.cyan;
      if (index % 4 == 1) c = Colors.blueGrey;
      if (index % 4 == 2) c = Colors.blue;
      if (index % 4 == 3) c = Color(0xFFea9999);
      return c;
    }
    if (filteredTests[index].type == 'باقة') {
      return PackageCardDesign(
        packageName: filteredTests[index].name,
        package:  '', 
        price: '${filteredTests[index].price} YR',
        details: filteredTests[index].details.toLowerCase(),
        colour: selectedColour(index),
        icon: Icons.ac_unit_outlined,
        type: filteredTests[index].type,
      );
    }
  } catch (e) {
    print(e);
  }
}

尝试的获取代码及错误

尝试了多种方式读取package数据,例如:

// 方法1
for (var entry in filteredTests[index].package.entries) {
  print(entry.key);
  print(entry.value);
}

// 方法2
List St = filteredTests[index].package.map((k,v) => MapEntry(k,v)).values.toList();
print (St);

// 方法3
Map<String, dynamic> data = filteredTests[index].package;
for (var entry in data['package'].entries) {
  print(entry.key);
  print(entry.value);
} 

每次都触发错误:

NoSuchMethodError: 方法'[]'在null上被调用。
I/flutter ( 3668): Receiver: null
I/flutter ( 3668): Tried calling:

问题原因及解决方法

核心问题

  1. 类型不匹配:Services类中package字段的默认值设为了空字符串'',但Test类中package定义为Map类型。当Firestore中没有package字段时,空字符串会被赋值给package,导致后续调用Map方法(如entries、[])时报错。
  2. 空值未处理:未先判断package是否为null就直接调用其方法,触发空指针异常。

解决方案

  1. 修正Services类的默认值:将package的默认值改为空Map,而非空字符串:
package: data['package'] ?? <String, dynamic>{},
  1. 明确Test类的类型:将package字段类型改为可空的Map类型,避免类型错误:
final Map<String, dynamic>? package;
  1. 安全读取package数据:在使用前先判断是否为null,再进行遍历:
// 在_card方法中读取package的示例
if (filteredTests[index].type == 'باقة') {
  final packageData = filteredTests[index].package;
  String packageContent = '';
  if (packageData != null) {
    packageData.forEach((key, value) {
      packageContent += '$key: $value\n';
      print('Key: $key, Value: $value');
    });
  }
  return PackageCardDesign(
    packageName: filteredTests[index].name,
    package: packageContent, // 传入处理后的package内容
    price: '${filteredTests[index].price} YR',
    details: filteredTests[index].details.toLowerCase(),
    colour: selectedColour(index),
    icon: Icons.ac_unit_outlined,
    type: filteredTests[index].type,
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:02:00