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

Flutter中读取Firebase实时数据库嵌套对象列表的问题

解决Flutter从Firebase实时数据库读取嵌套对象列表的类型不匹配问题

问题根源

  1. 错误的类型转换:直接将DataSnapshot强制转换为Lesson类型,Firebase返回的snapshot需先转为Map才能用实体类工厂方法解析。
  2. 未处理嵌套列表解析:实体类的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 21:57:47