Flutter中读取Firebase实时数据库嵌套对象列表的问题
解决Flutter从Firebase实时数据库读取嵌套对象列表的类型不匹配问题
问题根源
- 错误的类型转换:直接将
DataSnapshot强制转换为Lesson类型,Firebase返回的snapshot需先转为Map才能用实体类工厂方法解析。 - 未处理嵌套列表解析:实体类的
fromMap方法未将Firebase返回的动态列表(List<Object?>)转换为对应实体类列表(如List<QuestionGroup>),导致类型不匹配错误。
解决方案
步骤1:给所有实体类添加fromMap工厂方法,处理嵌套解析
修改每个实体类,添加支持嵌套列表解析的fromMap方法:
Answer类
class Answer { String? id; String? title; Answer({ this.id, this.title, }); factory Answer.fromMap(Map<dynamic, dynamic> map) { return Answer( id: map['id'], title: map['title'], ); } }
Question类
class Question { String? id; String? title; String? rightAnswer; List<Answer>? answers; Question({ this.id, this.title, this.answers, this.rightAnswer, }); factory Question.fromMap(Map<dynamic, dynamic> map) { List<Answer>? answers; if (map['answers'] != null) { answers = (map['answers'] as List) .map((answerMap) => Answer.fromMap(answerMap)) .toList(); } return Question( id: map['id'], title: map['title'], rightAnswer: map['rightAnswer'], answers: answers, ); } }
QuestionGroup类
class QuestionGroup { String? id; String? frenchWord; String? arabicWord; String? frenchTranslation; String? arabicTranslation; List<Question>? questions; QuestionGroup({ this.id, this.frenchWord, this.arabicWord, this.frenchTranslation, this.arabicTranslation, this.questions, }); factory QuestionGroup.fromMap(Map<dynamic, dynamic> map) { List<Question>? questions; if (map['questions'] != null) { questions = (map['questions'] as List) .map((questionMap) => Question.fromMap(questionMap)) .toList(); } return QuestionGroup( id: map['id'], frenchWord: map['frenchWord'], arabicWord: map['arabicWord'], frenchTranslation: map['frenchTranslation'], arabicTranslation: map['arabicTranslation'], questions: questions, ); } }
Lesson类(修改原有fromMap方法)
class Lesson { String? id; String? pdfLink; List<QuestionGroup>? questionGroups; List<Question>? questions; String? title; String? videoLink; String? yearId; Lesson({ this.id, this.pdfLink, this.questionGroups, this.questions, this.title, this.videoLink, this.yearId, }); factory Lesson.fromMap(Map<dynamic, dynamic> map) { List<QuestionGroup>? questionGroups; if (map['questionGroups'] != null) { questionGroups = (map['questionGroups'] as List) .map((groupMap) => QuestionGroup.fromMap(groupMap)) .toList(); } List<Question>? questions; if (map['questions'] != null) { questions = (map['questions'] as List) .map((questionMap) => Question.fromMap(questionMap)) .toList(); } return Lesson( id: map['id'], yearId: map['yearId'], title: map['title'], pdfLink: map['pdfLink'], videoLink: map['videoLink'], questionGroups: questionGroups, questions: questions, ); } }
步骤2:修改Firebase数据读取代码,正确解析每个快照
替换原有读取代码,先将DataSnapshot转为Map再解析:
await Firebase.initializeApp(); DatabaseReference lessonsRef = FirebaseDatabase.instance.ref('lessons'); lessonsRef.onValue.listen((event) { lessons?.clear(); // 清空列表避免重复添加数据 for (final child in event.snapshot.children) { final lessonMap = child.value as Map<dynamic, dynamic>; // 若数据库未存储id,可将节点key作为id赋值 lessonMap['id'] = child.key; final lesson = Lesson.fromMap(lessonMap); lessons?.add(lesson); log(lesson.title ?? '无标题'); // 打印标题验证解析结果 } }, onError: (error) { log('读取数据错误: $error'); });
关键说明
- 所有嵌套列表需通过
map方法逐个转换为对应实体类,Firebase返回的动态列表无法直接赋值给强类型实体列表。 - 若数据库中Lesson的id存储在节点key中,需手动将
child.key赋值给lessonMap的id字段,确保id字段有效性。
内容的提问来源于stack exchange,提问作者Ahmed El Sayed
相关产品推荐
相关产品推荐

