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

Android Hilt中数据库重下后实例引用更新问题求助

核心问题分析

Hilt会缓存SingletonComponent中提供的依赖实例(即使未显式标注@Singleton,Scoped组件内的无作用域绑定也可能被缓存),导致数据库文件替换后,已注入的ItemDao仍引用旧数据库实例。同时,ViewModel等Scoped组件会缓存注入的依赖,进一步加剧旧实例的残留问题。


解决方案

方案1:注入动态Dao提供者(推荐)

通过封装一个Dao获取类,每次使用时都从最新的数据库实例中获取Dao:

  1. 创建Dao提供者类
class ItemDaoProvider {
    fun get(): ItemDao {
        return ProjectDatabase.getDatabase().roomItemDao()
    }
}
  1. 修改Hilt Module
@Module
@InstallIn(SingletonComponent::class)
class ProjectDatabaseModule {
    @Provides
    fun provideItemDaoProvider(): ItemDaoProvider {
        return ItemDaoProvider()
    }
}
  1. 在依赖类中使用提供者
class InventoryViewModel @ViewModelInject constructor(
    private val itemDaoProvider: ItemDaoProvider
) : ViewModel() {
    fun queryItem(scanCode: String) {
        // 每次调用都获取最新的Dao实例
        val itemDao = itemDaoProvider.get()
        viewModelScope.launch {
            val item = itemDao.getItemByCode(scanCode)
            // 处理查询结果
        }
    }
}

方案2:使用Hilt内置Provider接口

利用Hilt的Provider接口实现动态实例获取:

  1. 修改Hilt Module
@Module
@InstallIn(SingletonComponent::class)
class ProjectDatabaseModule {
    @Provides
    fun provideProjectDatabaseProvider(): Provider<ProjectDatabase> {
        return Provider { ProjectDatabase.getDatabase() }
    }

    @Provides
    fun provideItemDaoProvider(dbProvider: Provider<ProjectDatabase>): Provider<ItemDao> {
        return Provider { dbProvider.get().roomItemDao() }
    }
}
  1. 在依赖类中使用Provider
class InventoryViewModel @ViewModelInject constructor(
    private val itemDaoProvider: Provider<ItemDao>
) : ViewModel() {
    fun queryItem(scanCode: String) {
        viewModelScope.launch {
            val item = itemDaoProvider.get().getItemByCode(scanCode)
            // 处理查询结果
        }
    }
}

关键注意事项

  1. 严格执行数据库替换流程:
    • 先停止所有数据库操作(如取消协程、禁用UI交互)
    • 调用ProjectDatabase.closeDatabase()关闭旧实例并置空INSTANCE
    • 删除/覆盖旧数据库文件
    • 下载新数据库文件到指定路径
    • 后续操作通过动态提供者获取新Dao实例
  2. 避免单例类直接注入Dao:单例类会长期持有旧实例,必须改用动态提供者方式获取Dao
  3. 修正Room初始化错误:原代码中createFromAsset(getDbNameWithPath())逻辑错误(getDbNameWithPath()指向filesDir路径,而非assets目录),应改为createFromFile(File(getDbNameWithPath())),确保从本地文件加载数据库

内容的提问来源于stack exchange,提问作者Péter Balogh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 16:00:48