如何从Firebase获取Array数据到Flutter?字符串可获取但Array报错
Flutter Firebase 获取字符串数组数据示例
问题场景
开发Flutter Pokédex应用时,可正常获取Firebase中的name、id、size等字符串字段,但读取elements数组字段时出错,需要实现正确的数组读取与展示逻辑。
修正后的完整代码示例
1. 数据模型优化(明确字符串数组类型)
把List<dynamic>改为List<String>,类型更严谨,避免类型转换异常:
class Pokemon { String id; final String name; final String size; final List<String> elements; Pokemon({ this.id = '', required this.name, required this.size, required this.elements, }); Map<String, dynamic> toJson() => { 'id': id, 'name': name, 'size': size, 'elements': elements, }; static Pokemon fromJson(Map<String, dynamic> json) => Pokemon( id: json['id'] ?? '', name: json['name'] ?? '', size: json['size'] ?? '', // 将Firebase返回的数组转为字符串列表,空值时返回空列表 elements: List<String>.from(json['elements'] ?? []), ); }
2. 实现Firebase数据读取Stream
补充readPokemon()方法,从Firebase Firestore中读取完整数据:
Stream<List<Pokemon>> readPokemon() { return FirebaseFirestore.instance .collection('pokemon') // 替换为你的Firebase集合名称 .snapshots() .map((snapshot) => snapshot.docs .map((doc) => Pokemon.fromJson(doc.data()..['id'] = doc.id)) .toList()); }
3. 数组数据展示(完善卡片构建方法)
实现buildPokemon方法,将数组元素(如宝可梦属性)友好展示:
Widget buildPokemon(Pokemon pokemon, BuildContext context) { return Card( margin: const EdgeInsets.all(8), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( pokemon.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text('体型: ${pokemon.size}'), const SizedBox(height: 8), const Text('属性:', style: TextStyle(fontWeight: FontWeight.w500)), // 遍历数组生成标签,自动换行避免溢出 Wrap( spacing: 6, children: pokemon.elements .map((element) => Chip( label: Text(element), backgroundColor: Colors.blue.shade100, )) .toList(), ), ], ), ), ); }
4. 完整页面代码(整合所有部分)
class PokedexHome extends StatefulWidget { const PokedexHome({super.key}); @override _PokedexHomeState createState() => _PokedexHomeState(); } class _PokedexHomeState extends State<PokedexHome> { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey, appBar: AppBar( leading: const Icon(Icons.sports_baseball), centerTitle: true, title: const Text('Pokédex'), backgroundColor: Colors.red, ), body: StreamBuilder<List<Pokemon>>( stream: readPokemon(), builder: (context, snapshot) { if (snapshot.hasError) { return const Text('找不到任何宝可梦 :('); } else if (snapshot.hasData) { final pokemonList = snapshot.data!; return GridView.count( crossAxisCount: 2, childAspectRatio: 1 / 0.5, children: pokemonList .map((pokemon) => buildPokemon(pokemon, context)) .toList(), ); } else { return const Center(child: CircularProgressIndicator()); } }, ), ); } Stream<List<Pokemon>> readPokemon() { return FirebaseFirestore.instance .collection('pokemon') .snapshots() .map((snapshot) => snapshot.docs .map((doc) => Pokemon.fromJson(doc.data()..['id'] = doc.id)) .toList()); } Widget buildPokemon(Pokemon pokemon, BuildContext context) { return Card( margin: const EdgeInsets.all(8), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( pokemon.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text('体型: ${pokemon.size}'), const SizedBox(height: 8), const Text('属性:', style: TextStyle(fontWeight: FontWeight.w500)), Wrap( spacing: 6, children: pokemon.elements .map((element) => Chip( label: Text(element), backgroundColor: Colors.blue.shade100, )) .toList(), ), ], ), ), ); } } class Pokemon { String id; final String name; final String size; final List<String> elements; Pokemon({ this.id = '', required this.name, required this.size, required this.elements, }); Map<String, dynamic> toJson() => { 'id': id, 'name': name, 'size': size, 'elements': elements, }; static Pokemon fromJson(Map<String, dynamic> json) => Pokemon( id: json['id'] ?? '', name: json['name'] ?? '', size: json['size'] ?? '', elements: List<String>.from(json['elements'] ?? []), ); }
关键注意点
- 安全类型转换:使用
List<String>.from(json['elements'] ?? [])替代强制类型转换,避免数组为空或类型不匹配时崩溃 - 空值处理:添加
?? ''和?? []处理字段为空的情况,增强代码健壮性 - 数组展示:用
Wrap+Chip的组合可自动换行展示多个数组元素,避免布局溢出问题
内容的提问来源于stack exchange,提问作者Mathias Van Langendonck
相关产品推荐
相关产品推荐

