Flutter中sqflite存储API JSON响应及本地数据同步问题咨询
看起来你已经顺利把API返回的JSON解析成List<Activities>了,但卡在了把这个列表同步到本地sqflite数据库这一步对吧?结合你提到本地CRUD、API单独CRUD都正常的情况,大概率是同步逻辑的细节处理出了问题,我来给你梳理几个关键排查点和解决方案:
1. 先确认批量存储的逻辑是否正确
首先你需要确保有针对Activities实体的数据库操作方法,尤其是批量插入/更新的逻辑:
单个活动的插入方法
先写好单个Activities对象转成Map并插入数据库的方法,这里要注意和你的表结构字段对应:
Future<void> insertActivity(Activities activity) async { final db = await _getDatabase(); // 替换成你的数据库实例获取方法 await db.insert( 'activities', // 你的表名 activity.toJson(), // 必须确保Activities类有toJson()方法,把对象转为sqflite可识别的Map conflictAlgorithm: ConflictAlgorithm.replace, // 处理重复数据:同ID则覆盖,根据需求调整 ); }
批量插入的优化(用事务提升效率)
直接遍历插入没问题,但用事务可以避免部分插入失败导致的数据不一致:
Future<void> bulkSyncActivities(List<Activities> activitiesList) async { final db = await _getDatabase(); await db.transaction((txn) async { for (final activity in activitiesList) { await txn.insert( 'activities', activity.toJson(), conflictAlgorithm: ConflictAlgorithm.replace, ); } }); }
⚠️ 重要提醒:必须保证Activities.fromJson()和toJson()的字段与数据库表的列完全匹配(包括字段名、数据类型),比如如果数据库列是activity_name,你的实体类字段不能是activityName(除非你在toJson里做了字段映射)。
2. 修复getData()的潜在空指针问题
看你的getData()代码,如果请求失败(statusCode !=200),list会处于未初始化状态,后续调用list.length或传入存储方法会直接报错!赶紧在方法开头初始化空列表:
Future<List<Activities>> getData() async { List<Activities> list = []; // 先初始化空列表,避免空指针 var res = await http.post( "http://xxxx/get-activity", headers: {HttpHeaders.authorizationHeader: "Bearer " + _token.toString()} ); if (res.statusCode == 200) { var data = json.decode(res.body); var rest = data["data"] as List; list = rest.map<Activities>((json) => Activities.fromJson(json)).toList(); } else { print('something error'); // 这里无需再赋值,因为已经初始化了空列表 } print("List Size: ${list.length}"); return list; }
3. 确保同步时机和异常处理
调用getData()后,要及时触发同步逻辑,并且加入异常捕获,方便定位问题:
// 示例:获取API数据并同步到本地的完整流程 Future<void> syncApiToLocal() async { try { final apiActivities = await getData(); if (apiActivities.isNotEmpty) { await bulkSyncActivities(apiActivities); print("✅ API数据已成功同步到本地数据库,共${apiActivities.length}条"); // 同步完成后可以刷新本地数据展示(比如通知UI更新) } else { print("⚠️ API返回数据为空,无需同步"); } } catch (e) { print("❌ 同步失败:$e"); // 这里可以加入错误上报或用户提示 } }
4. 排查数据冲突与同步策略
如果本地和API数据存在重复(比如相同ID的活动),你需要明确同步策略:
- 全量同步:用API数据覆盖本地所有数据,适合每次拉取最新全量数据的场景(用
ConflictAlgorithm.replace即可) - 增量同步:只同步API中比本地新的数据,这时候需要给
Activities加updatedAt时间戳字段,同步时先对比本地数据的时间,只插入/更新更新时间更晚的条目。
5. 验证数据解析的准确性
虽然你能解析出List,但最好打印解析后的对象,确认所有字段都正确解析:
list = rest.map<Activities>((json) => Activities.fromJson(json)).toList(); print("解析后的第一个活动:${list[0].toJson()}"); // 转成Map查看字段是否完整、类型是否正确
如果某个字段解析错误(比如日期格式不兼容、数字类型不匹配),插入sqflite时会抛出异常,导致同步失败。
内容的提问来源于stack exchange,提问作者santosh adhikari

