如何让Hilt重新创建已提供的Room数据库单例实例?
解决Hilt单例Room数据库注销后无法重建的问题
方案一:封装数据库管理类手动控制实例生命周期
创建单例的DatabaseManager由Hilt注入,内部负责Room实例的创建与重置,灵活控制生命周期:
- 定义
DatabaseManager类:
@Singleton class DatabaseManager @Inject constructor(@ApplicationContext private val context: Context) { private var appDatabase: AppDatabase? = null // 获取数据库实例,不存在则自动创建 fun getAppDatabase(): AppDatabase { return appDatabase ?: synchronized(this) { appDatabase ?: buildDatabase().also { appDatabase = it } } } // 重置数据库:关闭连接、删除文件、清空实例引用 fun resetDatabase() { appDatabase?.close() context.deleteDatabase("testdatabase") appDatabase = null } private fun buildDatabase(): AppDatabase { return Room.databaseBuilder( context, AppDatabase::class.java, "testdatabase" ) .fallbackToDestructiveMigration() .build() } }
- 移除原有的
provideRoomDatabase方法,在需要使用数据库的地方注入DatabaseManager,通过getAppDatabase()获取实例:
class SomeRepository @Inject constructor(private val databaseManager: DatabaseManager) { private val db = databaseManager.getAppDatabase() // ... 执行数据库操作 }
- 用户注销时调用
databaseManager.resetDatabase(),下次获取数据库时会自动重建新实例。
方案二:使用自定义作用域管理会话周期依赖
如果应用存在多个与用户会话绑定的依赖(不止数据库),可以创建自定义作用域,统一管理会话资源的生命周期:
- 定义自定义会话作用域:
@Scope @Retention(AnnotationRetention.RUNTIME) annotation class UserSessionScope
- 创建Hilt组件并关联该作用域:
@UserSessionScope @InstallIn(SingletonComponent::class) abstract class UserSessionComponent { companion object { fun create(context: Context): UserSessionComponent { return DaggerUserSessionComponent.builder() .context(context) .build() } } @BindsInstance abstract fun context(context: Context): UserSessionComponent abstract fun appDatabase(): AppDatabase }
- 在模块中提供作用域内的数据库实例:
@Module @InstallIn(UserSessionComponent::class) object UserSessionModule { @Provides @UserSessionScope fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase { return Room.databaseBuilder( context, AppDatabase::class.java, "testdatabase" ) .fallbackToDestructiveMigration() .build() } }
- 全局维护会话组件实例,登录时创建、注销时销毁:
object SessionManager { private var userSessionComponent: UserSessionComponent? = null fun initSession(context: Context) { userSessionComponent = UserSessionComponent.create(context) } fun getSessionComponent(): UserSessionComponent { checkNotNull(userSessionComponent) { "Session not initialized" } return userSessionComponent!! } fun clearSession(context: Context) { getSessionComponent().appDatabase().close() context.deleteDatabase("testdatabase") userSessionComponent = null } }
- 使用时通过
SessionManager获取数据库实例:
val db = SessionManager.getSessionComponent().appDatabase()
关键说明
- 方案一更适合仅需管理数据库实例的场景,实现简单直接;
- 方案二更适合多会话依赖的场景,能统一管理所有与用户绑定的资源;
- 两种方案均规避了
@Singleton的全局持久特性,让数据库实例可在注销后重新创建。
内容的提问来源于stack exchange,提问作者me.at.coding
相关产品推荐
相关产品推荐

