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

安卓应用更新后出现SQLiteDiskIOException崩溃的原因排查

问题分析:Room数据库更新后的SQLiteDiskIOException崩溃

问题背景

应用发布更新后出现磁盘I/O相关崩溃,此前为让asset中新增的数据库数据生效,将Room数据库版本从1升级到2,并使用fallbackToDestructiveMigration()配置。

崩溃日志

Fatal Exception: android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 1802 SQLITE_IOERR_FSTAT[1802]): , while compiling: PRAGMA cache_size
       at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
       at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1540)
       at android.database.sqlite.SQLiteConnection.executeForLong(SQLiteConnection.java:1075)
       at android.database.sqlite.SQLiteConnection.setCacheSizeFromConfiguration(SQLiteConnection.java:536)
       at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:416)
       at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:228)
       at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:758)
       at android.database.sqlite.SQLiteConnectionPool.tryAcquireNonPrimaryConnectionLocked(SQLiteConnectionPool.java:1355)
       at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:983)
       at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:619)
       at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:916)
       at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
       at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:63)
       at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
       at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
       at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:2278)
       at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:2253)
       at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.query(FrameworkSQLiteDatabase.kt:156)
       at androidx.room.RoomDatabase.query(RoomDatabase.kt:490)
       at androidx.room.util.DBUtil.query(DBUtil.kt:75)
       at myapppackage.data.datasource.db.language.MultiLanguageStationNameDao_Impl$1.call(MultiLanguageStationNameDao_Impl.java:37)
       at myapppackage.data.datasource.db.language.MultiLanguageStationNameDao_Impl$1.call(MultiLanguageStationNameDao_Impl.java:34)
       at androidx.room.CoroutinesRoom$Companion$createFlow$1$1$1.invokeSuspend(CoroutinesRoom.kt:128)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
       at java.lang.Thread.run(Thread.java:1012)

相关代码

数据库构建代码

private fun buildDatabase(context: Context): AppDatabase {
    return Room.databaseBuilder(
        context,
        AppDatabase::class.java, "new_database.db"
    ).createFromAsset("db/my_app_db.sqlite")
        .fallbackToDestructiveMigration()
        .build()
}

数据库版本配置

@Database(
    entities = [
        MultiLanguageStationNameEntity::class,
    ],
    version = 2
)

Repository代码

override fun getStationNames(): Flow<List<MultiLanguageStationNameRes>> {
    return multiLanguageStationNameDao.getStationNames()
        .map { entities ->
            entities.map {
                entity -> entity.asDomainModel()
           }
     }
}

Dao代码

@Dao
interface MultiLanguageStationNameDao {
    @Query("SELECT * FROM MultiLanguageStationName")
    fun getStationNames(): Flow<List<MultiLanguageStationNameEntity>>
}

崩溃原因解析

1. 核心崩溃本质

SQLiteDiskIOException(code 1802)属于磁盘层面的I/O异常,常见触发场景:

  • 设备存储空间不足
  • 存储硬件故障或文件系统损坏
  • 数据库文件被其他进程/线程占用,无法正常读写
  • 应用缺少数据库文件的访问权限

2. 应用更新时数据库处于打开状态的影响

这种情况是崩溃的潜在诱因:

  • 应用更新过程中,若旧版本后台进程未被系统完全杀死,仍持有数据库连接,会导致数据库文件处于被占用状态。
  • 新版本启动后尝试打开或替换数据库文件时,会因文件被锁触发磁盘I/O错误。

3. fallbackToDestructiveMigration的作用与影响

  • 该配置的逻辑是:当Room检测到版本不匹配且无对应迁移规则时,删除现有数据库文件,重新从asset复制新文件。
  • 如果更新时旧数据库连接未释放,执行删除旧文件的操作会因文件被占用触发I/O异常,这是本次崩溃的关键触发点之一。
  • 若设备存储空间不足,删除旧文件或复制新文件的操作也会直接触发这类错误。

排查与修复建议

  • 检查崩溃设备的存储状态:确认剩余空间充足,存储设备无故障
  • 优化数据库连接管理:确保应用退到后台或进程结束时,正确关闭所有数据库连接(Room单例实例需与应用生命周期绑定,避免泄漏)
  • 添加异常捕获:在数据库初始化或查询逻辑中捕获I/O异常,提供友好提示或重试机制
  • 提前清理旧数据库:新版本启动时,先检测旧数据库连接状态,确保释放后再执行迁移操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 16:33:24