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

如何基于Hilt实现多个ViewModel共享访问Room数据库

如何基于Hilt实现多个ViewModel共享访问Room数据库

嘿,我来帮你搞定这个问题!你之前的写法里每个ViewModel都自己初始化Room实例,不仅重复代码还容易造成资源浪费,用Hilt来做依赖注入刚好能完美解决多ViewModel共享同一个Room数据库实例的问题,而且代码会更干净易维护,完全符合Android的最佳实践。咱们一步步来实现:

1. 先添加必要的依赖

首先得在项目里引入Hilt和Room的相关依赖,打开你模块下的build.gradle(注意是Module级别的,不是Project级的),添加这些内容:

// 顶部添加Hilt插件
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

// 依赖部分
dependencies {
    // Hilt核心依赖
    implementation "com.google.dagger:hilt-android:2.48"
    kapt "com.google.dagger:hilt-android-compiler:2.48"

    // Room依赖
    implementation "androidx.room:room-runtime:2.6.1"
    implementation "androidx.room:room-ktx:2.6.1"
    kapt "androidx.room:room-compiler:2.6.1"
    // Room协程支持
    implementation "androidx.room:room-coroutines:2.1.0-alpha01"

    // ViewModel和协程相关(如果还没加的话)
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
}

// 配置kapt
kapt {
    correctErrorTypes = true
}

2. 配置Hilt的Application类

Hilt需要一个标注了@HiltAndroidApp的Application类作为入口,咱们创建一个:

@HiltAndroidApp
class MyApp : Application() {
    // 这里不需要写额外代码,Hilt会自动初始化
}

别忘了在AndroidManifest.xml里把Application指定为这个类:

<application
    android:name=".MyApp"
    ...>
    ...
</application>

3. 定义Room数据库和DAO

这部分和你原来的差不多,但要确保数据库是抽象类,DAO用@Dao注解:

// DAO接口
@Dao
interface DataDao {
    @Query("SELECT * FROM data")
    suspend fun getAll(): List<Data>

    // 其他增删改查方法按需添加
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertAll(dataList: List<Data>)
}

// 数据库类
@Database(entities = [Data::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
    abstract fun dataDao(): DataDao
}

这里的Data就是你的数据实体类,记得加@Entity注解哦。

4. 创建Repository层(关键!)

咱们把数据库操作封装在Repository里,ViewModel只和Repository交互,这样解耦性更强,也符合MVVM的架构规范:

class DataRepository @Inject constructor(
    private val dataDao: DataDao
) {
    suspend fun getAllData(): List<Data> {
        return dataDao.getAll()
    }

    // 其他数据操作方法,比如插入、删除,都在这里封装
    suspend fun insertData(dataList: List<Data>) {
        dataDao.insertAll(dataList)
    }
}

5. 用Hilt提供数据库和Repository的实例

现在写一个Hilt的Module,用来告诉Hilt怎么创建AppDatabase和Repository的实例,并且保证它们是单例的:

@Module
@InstallIn(SingletonComponent::class) // 绑定到SingletonComponent,整个应用生命周期只有一个实例
object DatabaseModule {

    @Provides
    @Singleton
    fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
        return Room.databaseBuilder(
            context,
            AppDatabase::class.java,
            "database"
        ).build()
    }

    @Provides
    fun provideDataDao(appDatabase: AppDatabase): DataDao {
        return appDatabase.dataDao()
    }

    @Provides
    @Singleton
    fun provideDataRepository(dataDao: DataDao): DataRepository {
        return DataRepository(dataDao)
    }
}

这里@Singleton注解保证了AppDatabase和Repository在整个应用中只有一个实例,所有ViewModel用的都是同一个数据库连接。

6. 在ViewModel里注入Repository

现在ViewModel不需要自己初始化数据库了,直接通过构造函数注入Repository,而且要用@HiltViewModel注解让Hilt能管理这个ViewModel:

@HiltViewModel
class DataViewModel @Inject constructor(
    private val dataRepository: DataRepository
) : ViewModel() {
    private val _mutableDataFlow = MutableStateFlow<List<Data>>(emptyList())
    val data: StateFlow<List<Data>> = _mutableDataFlow.asStateFlow()

    fun loadData() {
        viewModelScope.launch {
            _mutableDataFlow.value = dataRepository.getAllData()
        }
    }

    // 其他操作数据的方法,比如插入数据
    fun insertData(dataList: List<Data>) {
        viewModelScope.launch {
            dataRepository.insertData(dataList)
        }
    }
}

如果有其他ViewModel(比如另一个OtherViewModel),只需要同样用@HiltViewModel注解,构造函数注入DataRepository(或者对应其他数据的Repository)就可以了,完全不需要重复初始化数据库!

7. 在Activity/Fragment中使用ViewModel

最后,在Activity或者Fragment里,用Hilt的方式获取ViewModel,直接用by viewModels()就可以,Hilt会自动把依赖注入进去:

// 记得Activity要加@AndroidEntryPoint注解,Hilt才能注入
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val dataViewModel: DataViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 观察数据
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                dataViewModel.data.collect { dataList ->
                    // 更新UI
                }
            }
        }

        // 加载数据
        dataViewModel.loadData()
    }
}

Fragment的话同样要加@AndroidEntryPoint注解,然后用by viewModels()获取ViewModel。

总结一下

这样实现之后,所有的ViewModel都会共享同一个Room数据库实例,没有重复的数据库初始化代码,依赖注入让代码解耦,也符合Android的最佳实践。以后再新增ViewModel,只需要注入对应的Repository就行,非常方便。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 13:28:10