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

Flutter ListView Builder遇[]运算符错误,如何展示Firestore城市数据?

解决Flutter中FutureBuilder结合ListView展示Firestore数据的类型错误

遇到的错误

最初报错:

The method '[]' can't be unconditionally invoked because the receiver can be 'null'.

添加!强制非空后,又出现:

The operator '[]' isn't defined for the type 'Object'. Try defining the operator '[]'.

原始代码

FutureBuilder(
  future: getCity(),
  builder: ((context, snapshot) {
    if (snapshot.hasData) {
      var DocData = snapshot.data;

      print(DocData);
      return ListView.builder(itemBuilder: ((context, index) {
        final String? title = DocData["Cities"];
        return Text("testing");
      }));
    }
    return Text('Loading...');
  }))
],
),
),
),
);
}

Future getCity() async {
  var doc = await FirebaseFirestore.instance
      .collection('Listing')
      .doc('City')
      .get();
  return doc.data();
}

Firestore数据库结构

  • 集合:Listing
  • 文档:City
  • 字段:Cities(Map类型),键为城市名称,对应值是包含房源信息的数组,每个房源是含Price和Title的Map。

打印获取到的数据

{Cities: {Islamabad: [{Price: 100000, Title: Apartment}, {Price: 200000, Title: House}], Mirpur: [{Price: 300000, Title: House}]}}

解决方案

1. 给Future函数指定明确返回类型

默认返回Future<Object?>会导致类型不明确,指定为Future<Map<String, dynamic>?>,让Dart识别返回的是可索引的Map:

Future<Map<String, dynamic>?> getCity() async {
  var doc = await FirebaseFirestore.instance
      .collection('Listing')
      .doc('City')
      .get();
  return doc.data();
}

2. 安全解析嵌套数据

在FutureBuilder中先判断数据非空,再逐层解析Cities字段(注意它是Map而非字符串):

if (snapshot.hasData && snapshot.data != null) {
  final docData = snapshot.data!;
  final citiesMap = docData["Cities"] as Map<String, dynamic>;
  final cityNames = citiesMap.keys.toList(); // 提取城市名列表供ListView遍历

3. 适配ListView展示逻辑

设置itemCount为城市数量,在itemBuilder中获取对应城市的房源数据并展示:

return ListView.builder(
  itemCount: cityNames.length,
  itemBuilder: ((context, index) {
    final cityName = cityNames[index];
    final listings = citiesMap[cityName] as List<dynamic>;
    // 用折叠面板展示城市及下属房源
    return ExpansionTile(
      title: Text(cityName),
      children: listings.map((listing) {
        return ListTile(
          title: Text(listing["Title"]),
          subtitle: Text("价格: ${listing["Price"]}"),
        );
      }).toList(),
    );
  }),
);

修改后的完整代码

FutureBuilder<Map<String, dynamic>?>(
  future: getCity(),
  builder: ((context, snapshot) {
    if (snapshot.hasData && snapshot.data != null) {
      final docData = snapshot.data!;
      final citiesMap = docData["Cities"] as Map<String, dynamic>;
      final cityNames = citiesMap.keys.toList();

      return ListView.builder(
        itemCount: cityNames.length,
        itemBuilder: ((context, index) {
          final cityName = cityNames[index];
          final listings = citiesMap[cityName] as List<dynamic>;
          return ExpansionTile(
            title: Text(cityName),
            children: listings.map((listing) {
              return ListTile(
                title: Text(listing["Title"]),
                subtitle: Text("价格: ${listing["Price"]}"),
              );
            }).toList(),
          );
        }),
      );
    }
    return const Text('Loading...');
  }),
)

// ...

Future<Map<String, dynamic>?> getCity() async {
  var doc = await FirebaseFirestore.instance
      .collection('Listing')
      .doc('City')
      .get();
  return doc.data();
}

关键说明

  • 指定返回类型直接解决了Object无法使用[]的问题
  • 类型转换as明确了嵌套数据的结构,避免类型歧义
  • 将城市名转为列表,适配ListView的itemCount要求
  • 用ExpansionTile实现城市房源的折叠展示,提升界面可读性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 07:24:22