You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter+Firestore加载千张以上图片时报数据库锁警告并崩溃如何解决

database has been locked for 0:00:10.000000. Make sure you always use the transaction object for database operations during a transaction

问题原因

该报错本质是Firestore本地持久化依赖的SQLite数据库被长时间抢占锁触发超时,结合你的业务场景具体原因如下:

  • 一次性通过StreamBuilder拉取1000+条Firestore文档数据,大量快照写入本地持久化缓存时触发了高频数据库写入操作
  • cached_network_image同时发起上千张图片的并发下载和缓存写入请求,和Firestore的写入操作抢占本地数据库资源,导致锁冲突超时
  • 大规模并发IO操作耗尽设备系统资源,最终导致Flutter引擎和原生层连接断开,触发lost connection to device崩溃
  • 少量数据加载时IO压力小,不会触发锁冲突,因此运行正常
解决方案

1. 改造Firestore数据加载逻辑

不要一次性拉取全量1000+条数据,采用分页加载方案,每次仅加载当前视口及预加载区域需要的数据,示例代码如下:

// 首次查询,每页加载20条
Query wallpaperQuery = FirebaseFirestore.instance
    .collection('wallpapers')
    .orderBy('upload_time')
    .limit(20);

// 滚动到列表底部加载下一页时,用最后一条文档作为游标查询
Query nextPageQuery = wallpaperQuery.startAfterDocument(lastFetchedDoc).limit(20);

如果你的应用不需要离线访问Firestore数据,可以直接关闭本地持久化,从根源避免本地数据库写入冲突:

FirebaseFirestore.instance.settings = const Settings(
  persistenceEnabled: false,
);

2. 优化图片加载配置

调整cached_network_image的缓存和并发策略,降低IO压力:

  • 限制图片缓存尺寸,仅缓存和展示尺寸匹配的压缩图,避免写入超大原图到本地
  • 设置唯一缓存key,避免同一张图片重复下载缓存
  • 列表组件开启视图回收,取消不可见区域的图片加载请求
    示例配置:
CachedNetworkImage(
  imageUrl: wallpaperUrl,
  cacheKey: wallpaperId, // 用壁纸唯一ID作为缓存key
  maxHeightDiskCache: 800, // 按你实际展示的最大高度设置
  maxWidthDiskCache: 450,
  fit: BoxFit.cover,
)

使用GridView/ListView承载壁纸时添加如下配置,回收不可见项的资源:

ListView.builder(
  addAutomaticKeepAlives: false,
  addRepaintBoundaries: true,
  itemCount: wallpaperList.length,
  itemBuilder: (context, index) => // 你的壁纸项组件
)

3. 错峰IO操作

避免Firestore数据拉取和图片批量加载同时执行,可先拉取Firestore文档基础数据,再随列表滚动逐批触发图片加载,降低同一时间的IO并发量。

内容的提问来源于stack exchange,提问作者Aditya Hathlee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 06:54:01