Flutter中如何将Firebase检索到的数据正确追加到列表返回?
问题描述
我正尝试编写一个函数,用于从Firebase Realtime Database获取并返回文章列表,但该功能无法正常运行,我是Flutter开发新手。
我的数据库结构如下所示:
我编写的实现代码如下:
Future<List<ArticleModel>> getArticles() async { List<ArticleModel> articles = []; uid = FirebaseAuth.instance.currentUser!.uid; var ref = FirebaseDatabase.instance.ref().child("saved").child(uid); await ref.once().then((DatabaseEvent databaseEvent) { var docs = databaseEvent.snapshot.children; for (var element in docs) { Map<dynamic, dynamic> data = jsonDecode(jsonEncode(element.value)); var article = ArticleModel.fromJson(Map<dynamic, dynamic>.from(data)); articles.add(article); } }); print(articles);//此处打印结果为[Instance of 'ArticleModel', Instance of 'ArticleModel'....... return articles; }
ArticleModel类的实现代码如下:
class ArticleModel { String sourceName; String author; String title; String description; String url; String urlToImage; String publishedAt; ArticleModel( {required this.sourceName, required this.author, required this.title, required this.description, required this.urlToImage, required this.url, required this.publishedAt}); factory ArticleModel.fromJson(Map<dynamic, dynamic> element) { return ArticleModel( author: element['author'], description: element['desc'], sourceName: element['source'], publishedAt: element['time'], title: element['title'], url: element['url'], urlToImage: element['urlImage'], } }
问题原因
现有代码存在4个核心问题:
ArticleModel.fromJson工厂方法缺少闭合括号,属于语法错误,会直接导致编译不通过- 打印结果显示
Instance of 'ArticleModel'是Dart默认行为,不是数据获取失败:Dart打印类实例时默认不会输出实例内部属性,只输出类型标识 - 对Firebase返回的快照值做
jsonDecode(jsonEncode())二次转换属于冗余操作,Firebase返回的snapshot.value本身就是标准Map结构,多余的编解码反而可能触发类型转换异常 - 没有做空值兜底,当节点下无数据、或者某条文章缺少个别字段时,会直接抛出空指针错误
修复方案
1. 修正ArticleModel类,补全语法、增加空值兼容、重写toString方法方便调试
class ArticleModel { String sourceName; String author; String title; String description; String url; String urlToImage; String publishedAt; ArticleModel( {required this.sourceName, required this.author, required this.title, required this.description, required this.urlToImage, required this.url, required this.publishedAt}); // 重写toString方法,打印时直接显示属性内容 @override String toString() { return 'ArticleModel{sourceName: $sourceName, author: $author, title: $title, description: $description, url: $url, urlToImage: $urlToImage, publishedAt: $publishedAt}'; } factory ArticleModel.fromJson(Map<dynamic, dynamic> element) { // 增加空值兜底,避免数据库字段缺失导致崩溃 return ArticleModel( author: element['author'] ?? '', description: element['desc'] ?? '', sourceName: element['source'] ?? '', publishedAt: element['time'] ?? '', title: element['title'] ?? '', url: element['url'] ?? '', urlToImage: element['urlImage'] ?? '' ); // 补全之前缺失的右括号 } }
2. 优化数据获取函数,去掉冗余转换、增加空判断
Future<List<ArticleModel>> getArticles() async { List<ArticleModel> articles = []; final uid = FirebaseAuth.instance.currentUser!.uid; final ref = FirebaseDatabase.instance.ref().child("saved").child(uid); final databaseEvent = await ref.once(); // 节点无数据时直接返回空列表 if (databaseEvent.snapshot.value != null) { final docs = databaseEvent.snapshot.children; for (var element in docs) { // 直接转Map即可,不需要多余的json编解码 final data = Map<dynamic, dynamic>.from(element.value as Map); articles.add(ArticleModel.fromJson(data)); } } print(articles); // 重写toString后这里会打印完整的文章属性 return articles; }
3. 调用注意事项
getArticles()是异步方法,调用时必须加await,否则拿不到实际返回的列表:
// 正确调用示例 final articleList = await getArticles();
请核对数据库实际字段名和
fromJson中读取的key完全匹配,若数据库存储的字段名和代码中写的desc/source/time/urlImage不一致,对应修改即可,否则会读取到空值。
内容的提问来源于stack exchange,提问作者Anas Ansari
相关产品推荐
相关产品推荐

