Firestore StreamBuilder类型转换错误:List无法转为List<Map<String,dynamic>>
错误信息
The following _TypeError was thrown building StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(dirty, state: _StreamBuilderBaseState<DocumentSnapshot<Map<String, dynamic>>, AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> #954da):
type 'List' is not a subtype of type 'List<Map<String, dynamic>>' in type cast
场景与代码
我要实现和Firestore实时同步的棋盘展示功能,创建房间文档后用StreamBuilder拉取数据展示,却触发了上面的错误。相关代码如下:
Firestore监听方法
Stream<DocumentSnapshot<Map<String, dynamic>>> watchRoom(String roomId) { return FirebaseFirestore.instance.collection("rooms").doc(roomId).snapshots(); }
棋盘组件代码
class OnlineBoardWidget extends StatelessWidget { const OnlineBoardWidget({super.key}); @override Widget build(BuildContext context) { final columnCount = OnlineGameController.to.room.board.columnCount; final rowCount = OnlineGameController.to.room.board.rowCount; logger.t('build online board ($rowCount, $columnCount)'); return StreamBuilder( // 监听Firestore上的房间文档 stream: firestoreService.watchRoom("ec483c14-f414-44ae-bea1-b84e409331f0"), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); } else if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); } else { Map<String, dynamic> json = snapshot.data!.data()!; logger.i(json); // 能正常打印json数据 OnlineRoom room = OnlineRoom.fromJson(json); // 此处触发错误 logger.i(room); return Text(room.toString(), style: kNormalText,); } }, ); } }
测试情况
我怀疑是OnlineRoom.fromJson()的问题,于是在main函数里写了测试代码,直接用本地JSON片段调用fromJson()完全正常,没有报错:
测试代码
final object = OnlineRoom.fromJson(roomJsonSnippet); logger.i(object); // 无错误,正常打印对象
测试用JSON片段
{ "winCount": 5, "historyBoard": { "cells": { "0": [ { "column": 0, "row": 0, "state": "normal", "content": "noSeed" }, { "column": 1, "row": 0, "state": "normal", "content": "noSeed" } ], "1": [ { "column": 0, "state": "normal", "row": 1, "content": "noSeed" }, { "column": 1, "row": 1, "state": "normal", "content": "noSeed" } ] }, "rowCount": 2, "columnCount": 2 }, "name": "Untitled Room", "historyRoundIndex": 0, "id": "ec483c14-f414-44ae-bea1-b84e409331f0", "state": "playing", "rounds": [ { "historyTurns": [], "currentPlayerIndex": 0, "_historyPlayerIndex": 0, "players": [ { "score": 0, "finalScore": null, "seed": "cross", "name": "Player 1", "initialScore": 0, "index": 0 }, { "score": 0, "finalScore": null, "seed": "nought", "initialScore": 0, "name": "Player 2", "index": 1 } ], "historyTurnIndex": 0, "winTurnIndex": null, "index": 0, "currentTurnIndex": 0, "winnerIndex": null, "turns": [] } ], "board": { "cells": { "0": [ { "column": 0, "state": "normal", "row": 0, "content": "noSeed" }, { "column": 1, "row": 0, "state": "normal", "content": "noSeed" } ], "1": [ { "column": 0, "state": "normal", "row": 1, "content": "noSeed" }, { "column": 1, "row": 1, "state": "normal", "content": "noSeed" } ] }, "rowCount": 2, "columnCount": 2 }, "currentRoundIndex": 0 }
疑问
为什么本地测试fromJson()正常,但从Firestore拉取数据调用就会出现类型转换错误?
解决方案
核心原因
Firestore返回的数组是List<dynamic>类型,而非Dart中严格的List<Map<String, dynamic>>。你的fromJson方法如果直接将其强制转换为List<Map<String, dynamic>>,就会触发类型错误。而本地JSON是直接用Dart构造的Map<String, dynamic>,其中的List已经是List<Map<String, dynamic>>类型,所以不会报错。
修复步骤
- 修改
fromJson中的List转换逻辑:不要直接强制类型转换,显式遍历List并转换每个元素的类型。
比如原本的错误写法:
改成:List<Map<String, dynamic>> cellsList = json['cells'] as List<Map<String, dynamic>>;List<Map<String, dynamic>> cellsList = (json['cells'] as List<dynamic>) .map((item) => item as Map<String, dynamic>) .toList(); - 检查所有嵌套数组:重点处理
board.cells、historyBoard.cells、rounds、players这些嵌套结构里的数组,确保所有List都经过显式类型转换。 - 可选:使用代码生成工具:比如
json_serializable包,它生成的fromJson方法会自动兼容Firestore返回的动态类型List,避免手动转换的错误。
验证方法
修改后重新运行StreamBuilder,确认错误消失。也可以在fromJson中打印Firestore返回List的runtimeType,对比本地测试的List类型,确认差异已解决。
内容的提问来源于stack exchange,提问作者Thắng Nguyễn

