Flutter sqflite列表加载3条数据后返回页面崩溃问题
解决Sqflite列表数据≥3条时返回页面崩溃的问题
常见触发原因及对应解决方案
1. FutureBuilder的Future重复创建导致状态混乱
如果在build方法里直接调用数据库查询方法(比如_db.getStats()),每次页面重建都会生成新的Future。当从添加页面返回时,旧的Future可能还在执行,新的Future又开始,导致ListView拿到不一致的数据,触发Sliver断言错误。
解决办法:把Future存到State变量中,在initState里初始化:
late Future<List<BodyStats>> _statsFuture; @override void initState() { super.initState(); _statsFuture = _databaseHelper.fetchBodyStats(); } // 后续在FutureBuilder中使用这个预初始化的Future FutureBuilder<List<BodyStats>>( future: _statsFuture, builder: (context, snapshot) { // 构建UI逻辑 }, )
2. ListView的itemCount与实际数据长度不匹配
当数据数量变化时,如果itemCount没有和snapshot.data的长度严格对应,或者错误/加载状态下返回了多个子项,就会触发Sliver的断言错误。
检查&修复点:
- 仅在
snapshot.hasData时渲染ListView,且itemCount设为snapshot.data!.length - 加载/错误/空数据状态下,返回单个中心Widget(而非ListView子项)
示例代码:
builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('暂无数据')); } // 数据正常时渲染列表 return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) { final stat = snapshot.data![index]; return ListTile( title: Text('体重: ${stat.weight}kg'), subtitle: Text(stat.date.toString()), ); }, ); }
3. 从添加页面返回后未刷新数据
如果添加新数据后,没有重新获取数据库数据,FutureBuilder会继续使用旧的Future,导致内存中的数据和实际数据库数据不一致,触发断言。
解决办法:利用Navigator.push的返回值触发数据刷新:
// 在BodyStatsListScreen中跳转添加页面 final updateTrigger = await Navigator.push( context, MaterialPageRoute(builder: (context) => AddBodyStatsScreen()), ); // 若添加页面返回标记,重新获取数据 if (updateTrigger == true) { setState(() { _statsFuture = _databaseHelper.fetchBodyStats(); }); } // 在AddBodyStatsScreen中完成添加后返回标记 Navigator.pop(context, true);
4. 数据模型转换存在空值/类型错误
如果从数据库读取的数据未正确转换为模型(比如null值未处理、类型不匹配),构建列表项时会抛出异常,间接触发Sliver断言。
检查点:
- 确保模型的
fromMap方法处理所有字段,避免null或类型转换错误 - 比如处理数值类型时,用
(map['weight'] as num).toDouble()而非直接强转
示例模型转换:
class BodyStats { final int id; final double weight; final DateTime recordDate; BodyStats({required this.id, required this.weight, required this.recordDate}); factory BodyStats.fromMap(Map<String, dynamic> map) { return BodyStats( id: map['id'] as int, weight: (map['weight'] as num).toDouble(), recordDate: DateTime.parse(map['record_date'] as String), ); } }
排查步骤总结
- 确认FutureBuilder的Future是在
initState初始化,而非build方法内 - 检查ListView的
itemCount是否与数据长度严格一致,异常状态返回单个Widget - 从添加页面返回时,手动触发数据刷新
- 验证数据模型的转换逻辑,确保无空值或类型错误
内容的提问来源于stack exchange,提问作者Julien
相关产品推荐
相关产品推荐

