Flutter中sqflite删除数据行无效问题求助
解决Flutter中sqflite删除数据不生效及图片删除后加载报错问题
问题现象
- 使用sqflite删除数据行无报错,但重新获取数据时该行仍存在
- 执行
await favPlace.image.delete()后,重新加载页面因图片文件已删除出现报错
修复方案
一、解决数据库删除不生效问题
问题根源:removePlace中先更新本地state再执行数据库删除,若数据库操作未成功(或未完成),本地状态临时更新,但重新拉取数据时会从数据库恢复旧数据;同时缺少错误捕获,无法排查删除失败原因。
修改removePlace函数:
Future<void> removePlace(FavoritePlace favPlace) async { final db = await _getDatabase(); try { // 先执行数据库删除,确保数据持久化层先更新 final deletedCount = await db.delete( _tableName, where: 'id = ?', whereArgs: [favPlace.id], ); print('Deleted rows count: $deletedCount'); // 仅当数据库删除成功(影响行数>0)时,再更新本地状态 if (deletedCount > 0) { state = state.where((place) => place.id != favPlace.id).toList(); // 图片删除放在状态更新后,避免UI还未更新就丢失图片导致异常 await favPlace.image.delete(); } } catch (e) { print('Delete operation failed: $e'); // 可根据需求添加用户可见的错误提示 } finally { await db.close(); } }
二、解决图片删除后加载报错问题
问题根源:数据库中仍保留已删除图片的路径,getPlaces直接根据路径创建File对象,加载时因文件不存在触发报错。
修改getPlaces函数:
Future<void> getPlaces() async { final db = await _getDatabase(); final dataOfDb = await db.query(_tableName); final validPlaces = <FavoritePlace>[]; final invalidIds = <String>[]; for (final row in dataOfDb) { final imagePath = row['image'] as String; final imageFile = File(imagePath); // 检查图片文件是否存在,仅保留有效数据 if (await imageFile.exists()) { validPlaces.add(FavoritePlace( id: row['id'] as String, title: row['title'] as String, image: imageFile, favLocation: FavoriteLocation( latitude: row['lat'] as double, longitude: row['lng'] as double, address: row['address'] as String, ), )); } else { // 记录无效数据ID,后续清理数据库 invalidIds.add(row['id'] as String); } } // 清理数据库中的无效数据 if (invalidIds.isNotEmpty) { await db.delete( _tableName, where: 'id IN (${List.filled(invalidIds.length, '?').join(',')})', whereArgs: invalidIds, ); } state = validPlaces; await db.close(); }
三、页面代码优化
问题:onDismissed中调用异步的removePlace但未等待完成,且多余的setState会导致不必要的UI重建。
修改onDismissed回调:
onDismissed: (_) async { await ref.read(favoritePlaceProvider.notifier).removePlace(favList[index]); // 移除setState,Riverpod会自动监听state变化更新UI },
额外优化addPlace函数:
当前addPlace返回类型为void但内部使用async,改为Future<void>确保调用方可等待操作完成,同时调整状态更新顺序,保证数据一致性:
Future<void> addPlace(FavoritePlace favPlace) async { final appDir = await app_path.getApplicationDocumentsDirectory(); final imageName = path.basename(favPlace.image.path); final cImage = await favPlace.image.copy('${appDir.path}/${favPlace.id[3]}$imageName'); final db = await _getDatabase(); await db.insert(_tableName, { 'id': favPlace.id, 'title': favPlace.title, 'image': cImage.path, 'lat': favPlace.favLocation.latitude, 'lng': favPlace.favLocation.longitude, 'address': favPlace.favLocation.address, }); await db.close(); // 数据库操作完成后再更新本地状态 state = [...state, favPlace.copyWith(image: cImage)]; print('db closed'); }
内容的提问来源于stack exchange,提问作者Talat Saleh
相关产品推荐
相关产品推荐

