如何解决ListView中‘type 'int' is not a subtype of type 'String'’错误?
问题描述
我用以下代码从Firebase获取数据填充menuItemList,用于ListView展示:
Future<void> allMenuDetail(String orderID) async { _streamSubscriber = _dbRef.child('MenuItem/$orderID').onValue.listen((event) { if (event.snapshot.value != null) { var data = event.snapshot.value as Map; var price = data['price']; var itemName = data['itemName']; var desc = data['description']; var itemImg = data['img']; // String itemID = data['id']; Map<String, dynamic> myMap = { 'price': price, 'itemName': itemName, 'desc': desc, 'img': itemImg, 'itemID': itemID }; List<dynamic> shortList = [myMap]; menuItemList.addAll(shortList); setState(() {}); } else { } }); }
但在ListView部分出现type 'int' is not a subtype of type 'String'错误,错误指向标注行,ListView代码如下:
Expanded( child: ListView.builder( itemCount: menuItemList.length, itemBuilder: (context, index) { final item = menuItemList[index];//Error shows up here String price = item['price']; String itemName = item['itemName']; String desc = item['description']; String itemImg = item['img']; String itemID = item['itemID']; print('!'); // var cartPorducts = item['cartProducts']; return Container( height: 95, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24)), margin: const EdgeInsets.fromLTRB(8, 10, 8, 10), child: InkWell( onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => ItemPageState( path: categoryPath, itemName: itemName, desc: desc, price: 9, itemImg: itemImg, id: itemID))); // } }, child: Card( margin: const EdgeInsets.fromLTRB(8, 10, 8, 10), color: Colors.white, clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ ClipRect( child: Align( alignment: Alignment.center, widthFactor: 0.8, child: Image( image: AssetImage(itemImg), height: 100, width: 150, fit: BoxFit.cover, ), )), const SizedBox(width: 30), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( itemName, style: const TextStyle( color: Colors.black, fontSize: 25), ), Text( 'Price: R', //+ price.toString(), style: const TextStyle( color: Colors.black, fontSize: 18), ), ], ), const SizedBox(width: 30), ]), ))); }, ))
其他地方用相同方式实现正常,请问问题出在哪里?
问题原因及解决方案
核心问题:类型不匹配
错误提示type 'int' is not a subtype of type 'String',本质是你把int类型的值强制赋值给String类型变量,主要有两个关键点:
price的类型冲突
从Firebase读取的price大概率是整数类型(数据库中存的是数字),但你在ListView里直接写String price = item['price'];,试图将int直接转为String,触发类型转换错误。itemID未正确初始化
你注释掉了String itemID = data['id'];,但在myMap里仍引用itemID,导致该变量未定义,后续赋值给String itemID也会引发潜在问题。
具体修改步骤
处理
price类型转换:将String price = item['price'];改为安全的类型转换:// 方式1:直接转String String price = item['price'].toString(); // 方式2:先存为int再按需转换 int priceInt = item['price']; String price = priceInt.toString();修复
itemID的赋值:取消注释String itemID = data['id'];,确保从数据库正确读取itemID:String itemID = data['id']; // 取消这行的注释其他字段的安全校验:如果
itemName、desc等字段在数据库中可能不是String类型,建议添加空安全转换:String itemName = item['itemName']?.toString() ?? ''; String desc = item['description']?.toString() ?? '';
额外优化建议
建议创建MenuItem实体类,用类型化方式存储数据,彻底避免动态类型带来的错误:
class MenuItem { final int price; final String itemName; final String desc; final String img; final String itemID; MenuItem({ required this.price, required this.itemName, required this.desc, required this.img, required this.itemID, }); factory MenuItem.fromMap(Map<String, dynamic> map) { return MenuItem( price: map['price'] as int, itemName: map['itemName'] as String, desc: map['description'] as String, img: map['img'] as String, itemID: map['id'] as String, ); } }
获取数据时转换为实体类:
MenuItem menuItem = MenuItem.fromMap(data); menuItemList.add(menuItem);
之后在ListView里直接调用类型化属性,无需再做类型转换。
内容的提问来源于stack exchange,提问作者Stamp777

