Flutter使用sqflite时Future<List<Item>>无length属性报错解决方案咨询
错误原因
你遇到的两个报错分别由以下原因导致:
The getter 'length' isn't defined for the class 'Object':使用FutureBuilder时未指定泛型,Dart无法推断snapshot.data的类型,默认识别为通用Object类,自然不存在length属性。A non-null value must be returned since the return type 'Widget' doesn't allow null:FutureBuilder的builder方法要求所有逻辑分支都必须返回非空Widget,你之前的代码没有覆盖加载中、加载失败、无数据等分支,存在返回null的情况,违反空安全规则。
解决方案
方案1:直接修正FutureBuilder写法
给FutureBuilder明确指定List<Item>泛型,同时覆盖所有状态分支返回对应Widget:
// 先在页面内初始化ItemsController final ItemsController itemsController = Get.put(ItemsController()); @override Widget build(BuildContext context) { return FutureBuilder<List<Item>>( // 注意不要直接把loadAllItems写在这,避免每次组件重建重复请求,实际使用可提前存在变量中 future: itemsController.loadAllItems(), builder: (context, snapshot) { // 加载中状态 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 加载失败状态 if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } // 无数据状态 if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('暂无待办事项')); } // 有数据时返回列表 final itemList = snapshot.data!; return ListView.builder( itemCount: itemList.length, itemBuilder: (context, index) { final currentItem = itemList[index]; // 替换为你自己的列表项组件 return ListTile( title: Text(currentItem.name ?? '未命名待办'), subtitle: Text(currentItem.notes ?? '无备注'), ); }, ); }, ); }
方案2:适配GetX的响应式方案(更推荐)
既然你已经用了GetX作为状态管理,可直接将列表转为响应式变量,避免反复写FutureBuilder:
- 先修改
ItemsController:
class ItemsController extends GetxController { // 原有代码保持不变 // 新增响应式待办列表 final RxList<Item> items = <Item>[].obs; // 新增拉取数据并更新列表的方法 Future<void> fetchAllItems() async { final dbController = DBController(); final List<Map<String, dynamic>> itemsMaps = await dbController.query(tableItems); items.value = List.generate(itemsMaps.length, (i) => Item.fromMap(itemsMaps[i])); } // 修改addItem方法,新增数据后自动刷新列表 Future<int> addItem(Item item) async { final dbController = DBController(); int id = await dbController.insertElement(tableItems, item); await fetchAllItems(); return id; } // 后续update、delete方法实现后也调用fetchAllItems即可自动刷新列表 }
- 页面中直接用
Obx监听列表变化构建视图:
final ItemsController itemsController = Get.put(ItemsController()); @override void initState() { super.initState(); // 页面初始化时拉取一次数据 itemsController.fetchAllItems(); } @override Widget build(BuildContext context) { return Obx(() { if (itemsController.items.isEmpty) { return const Center(child: Text('暂无待办事项')); } return ListView.builder( itemCount: itemsController.items.length, itemBuilder: (context, index) { final currentItem = itemsController.items[index]; return ListTile( title: Text(currentItem.name ?? '未命名待办'), subtitle: Text(currentItem.notes ?? '无备注'), ); }, ); }); }
额外优化建议
修改Item类的fromMap方法参数类型,避免隐式类型转换警告:
// 把原方法的Map改为Map<String, dynamic> Item.fromMap(Map<String, dynamic> map) { this._id = map[colId]; this._name = map[colName]; this._notes = map[colNotes]; this._expiryDate = map[colExpiryDate]; this._category = map[colCategory]; this._quantity = map[colQuantity]; }
内容的提问来源于stack exchange,提问作者mlazzarotto91
相关产品推荐
相关产品推荐

