【问题标题】:Flutter: Parsing Firebase Realtime Database snapshot to listFlutter:解析 Firebase 实时数据库快照以列出
【发布时间】:2020-04-28 23:10:15
【问题描述】:

我尝试搜索其他问题,但唯一与此类似的问题在 JavaScript 而不是 Dart/Flutter 中有答案。我正在尝试将我的 Firebase 实时数据库中的列表作为List<BaseModel> 获取到我的应用程序中@

到目前为止,从我在网上搜索的内容来看,我认为DataSnapshot 的结果是我可以解析的地图,所以我尝试了一下,但得到了这个错误:List<dynamic>' is not a subtype of type 'Map<dynamic, dynamic>

我的代码:

Future<List<BaseModel>> getList(
    {DatabaseReference query, Models modelType}) async {
  List<BaseModel> list = new List();
  DataSnapshot snap = await query.once();
  Map<String, dynamic> json = Map.from(snap.value);
  json.forEach((key, value) {
    list.add(BaseModel(model: modelType, key: key, snapshot: value));
  });
  return list;
}

奇怪的是,即使我尝试解析非列表模型,我也会得到同样的错误。

我的数据库结构如下:

更新:

基础模型:

abstract class BaseModel {
  factory BaseModel({Models model, String key, Map map}) {
    switch (model) {
      case Models.MyModel:
        return MyMod.fromSnapshot(key: key, map: map);
        break;
      default:
        throw ("Not a valid model.");
    }
  }
}

我的模特:

MyModel.fromSnapshot({String key, Map map}) {
  _id = key;
  _title = map['title'];
}

我的 Firebase 查询只是 .child("Root") 的数据库引用

【问题讨论】:

  • 能否分享您的 BaseModel 和 Firebase 查询?
  • 附言。我可以只添加 100,因为我存储的项目数量少于每个节点的数量,但是如果您的密钥没有上限,那么您只需要对其进行编码,以便它以非零值开头,我猜。
  • 您好,我添加了 BaseModel 和查询

标签: flutter dart


【解决方案1】:

我找到了解决办法!

我的新代码:

Future<List<BaseModel>> getList({DatabaseReference query, Models modelType}) async {
  List<BaseModel> list = new List();
  DataSnapshot snap = await query.once();
  List<dynamic> resultList = snap.value;
  for(var i = 0; i < resultList.length; i++) {
    Map<dynamic, dynamic> map = Map.from(resultList[i]);
    list.add(BaseModel(model: modelType, key: i.toString(), snapshot: map));
  }
  return list;
}

假设您从模型的 .fromMap(yourMap) 构造函数方法中解析值,这应该可以工作。类似_title = yourMap['key'];

【讨论】:

    【解决方案2】:

    我也有类似的经历,snapshot.value 有时会返回 List,有时会返回 Map。我搜索了很长时间才得到答案,但我想出了一个解决方法。 我怀疑问题是由使用值为 0 的记录键引起的,因此我在将每个键写入数据库之前将其添加了 100,然后在读取并处理记录时将其减去。问题消失了,因为我总是得到一个地图返回。 从那以后,我看到了这种行为的原因,它确认零键值是罪魁祸首,但不幸的是我没有保存链接。我认为这是在 Firebase 博客之一上。 我认为 0 记录返回一个列表,而具有正值的记录返回一个地图。 不管怎样,试试加 100 的技巧,看看有没有帮助。如果有帮助,请给我投票....我认为您不需要代码来添加或删除 100。:-)

    找到这篇文章,Firebase 正在根据快照内容决定是渲染数组还是地图:https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html?m=1

    更新:

    对不起,我的“从 0 开始”理论是一个转移注意力的理论。

    这种行为的关键(粗体中的位)位于 Firebase 博客(上面的链接)的部分中,该部分指出:

    但是,为了帮助在 Firebase 中存储数组的人,当您 调用 .val() 或使用 REST api 读取数据,如果数据看起来像 数组,Firebase 会将其呈现为数组。

    特别是,如果所有的键都是整数,并且超过一半 对象中 0 和最大键之间的键不为空 值,然后 Firebase 会将其呈现为数组。 后面的部分是 重要的是要记住。

    // 我们发送这个 ['a', 'b', 'c', 'd', 'e'] // Firebase 存储这个 {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}

    // 因为键是数字和顺序的, // 如果我们查询数据, 我们得到这个 ['a', 'b', 'c', 'd', 'e']

    // 但是,如果我们随后删除 a、b 和 d,// 它们不再是 大部分是顺序的,所以 // 我们没有返回数组 {2: 'c', 4: 'e'} 您目前无法更改或阻止此行为。

    我现在通过设置如下图所示的 db 节点对此进行了测试。我使用snapshot.value is Listsnapshot.value is Map 测试了snapshot.value 中返回的内容,均返回true 或false。

    当只有节点 0、1 和 3 存在时,Firebase RTDB 很高兴在 snapshot.value 中返回一个列表。当我添加数据不一致的节点 4 和 6 时,它决定是时候返回一个 Map。 :-)

    因此,快速解决方法是使用 is List 和/或 is Map 测试 snapshot.value 的内容,然后相应地处理内容,否则重新考虑您的密钥...它们是顺序的或关闭的事实-顺序(有间隙)但具有相同的子结构是问题。

    【讨论】:

    • 我认为这与密钥为 0 无关。我尝试更改数据库以使用字符串作为其密钥,但仍然遇到相同的错误
    猜你喜欢
    • 2022-01-21
    • 2021-01-21
    • 2019-11-01
    • 2021-10-01
    • 1970-01-01
    • 2021-06-09
    • 2021-03-26
    • 2021-06-07
    • 1970-01-01
    相关资源
    最近更新 更多