Flutter报NoSuchMethodError:bool类无'[]'实例方法异常排查
问题描述
运行程序时抛出未处理异常:Unhandled Exception Error: NoSuchMethodError,具体报错信息为bool类型的类不存在名为'[]'的实例方法。
该异常触发场景为编写从Firebase实时数据库拉取商品数据的fetchAndSetProducts异步方法,对应异常代码如下:
Future<void> fetchAndSetProducts() async { const url = 'https://flutter-shop-2b595-default-rtdb.asia-southeast1.firebasedatabase.app/products.json'; try { final response = await http.get(url); final extractedData = json.decode(response.body) as Map<String, dynamic>; final List<Product> loadedProducts = []; extractedData.forEach((prodId, prodData) { loadedProducts.add(Product( id: prodId, title: prodData['title'], description: prodData['description'], price: prodData['price'], imageUrl: prodData['imageUrl'])); }); _items = loadedProducts; notifyListeners(); //print(json.decode(response.body)); } catch (error) { rethrow; } }
异常触发原因
- 核心问题是代码做了非安全的类型强转:默认
json.decode(response.body)的返回值一定是Map<String, dynamic>结构,且遍历出的每个商品节点prodData也一定是Map类型,但实际运行时拿到的某一层级值为布尔类型,代码却用下标[](Map专属的取值操作)去读取布尔值的属性,就会触发该NoSuchMethodError。 - 常见触发场景分两类:
- 数据侧问题:Firebase实时数据库对应products路径下存在脏数据,比如某个商品节点整体被存为true/false布尔值,或商品下的某字段(预期为字符串/数值的title、price等)实际存为布尔值。
- 逻辑侧问题:请求未成功(比如权限配置错误、路径不存在)时,Firebase返回的结构不是预期的商品Map,可能返回布尔值、错误信息字符串或null,代码未做响应状态和数据类型校验就直接强转遍历,触发类型错误。
修复方案
按以下步骤修改代码即可解决问题:
- 增加HTTP响应状态校验,仅当响应状态码为2xx(请求成功)时才执行数据解析逻辑,非成功状态直接抛出对应错误,避免解析错误结构的返回值。
- 取消强制类型转换,增加数据类型判断:解码后先判断返回值是否为预期的
Map<String, dynamic>类型,如果是null、布尔值等非预期类型,直接返回空商品列表即可。 - 遍历商品节点时,先判断当前节点数据是否为Map类型,跳过类型不匹配的脏数据;读取单个商品字段时增加类型兼容和默认值兜底,避免单字段类型错误导致整个解析流程崩溃。
修复后的完整代码如下:
Future<void> fetchAndSetProducts() async { const url = 'https://flutter-shop-2b595-default-rtdb.asia-southeast1.firebasedatabase.app/products.json'; try { final response = await http.get(url); // 校验请求成功状态 if (response.statusCode >= 200 && response.statusCode < 300) { final decodeData = json.decode(response.body); // 兼容返回非Map结构的场景 if (decodeData is! Map<String, dynamic>) { _items = []; notifyListeners(); return; } final extractedData = decodeData; final List<Product> loadedProducts = []; extractedData.forEach((prodId, prodData) { // 跳过非Map类型的脏数据节点 if (prodData is! Map<String, dynamic>) return; loadedProducts.add(Product( id: prodId, title: prodData['title']?.toString() ?? '', description: prodData['description']?.toString() ?? '', price: (prodData['price'] as num?)?.toDouble() ?? 0.0, imageUrl: prodData['imageUrl']?.toString() ?? '' )); }); _items = loadedProducts; notifyListeners(); } else { throw Exception('商品数据拉取失败,状态码:${response.statusCode}'); } } catch (error) { rethrow; } }
内容的提问来源于stack exchange,提问作者Yogesh Joshi
相关产品推荐
相关产品推荐

