如何结合Coroutines与Flow实现Room Database的Repository及ViewModel?
集成Coroutines与Flow重构Room的Repository和ViewModel
Repository绝对不是多余的——它是解耦UI层和数据层的核心角色,负责统一管理本地(Room)和可能的远程数据源,让代码更易维护和测试。下面一步步教你集成Coroutines与Flow来重构,全程不用Hilt,聚焦核心逻辑:
1. DAO层:用Flow实现数据自动监听
Room原生支持Flow,DAO的查询方法直接返回Flow<数据类型>即可,Room会自动在后台线程执行查询,且数据变化时自动推送给下游。
先定义实体类:
@Entity(tableName = "users") data class User( @PrimaryKey val id: Int, val name: String, val email: String )
然后写DAO接口:
@Dao interface UserDao { // 查询所有用户,返回Flow,Room自动后台执行+数据变化通知 @Query("SELECT * FROM users") fun getAllUsers(): Flow<List<User>> // 增删改加suspend修饰,必须在Coroutine中调用(Room已默认处理线程切换) @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertUser(user: User) @Delete suspend fun deleteUser(user: User) }
2. Repository层:封装数据源,暴露Flow给ViewModel
Repository持有DAO实例,封装所有数据操作逻辑,ViewModel只和它交互,不用关心数据来自本地还是远程。
class UserRepository(private val userDao: UserDao) { // 直接暴露DAO的Flow,ViewModel可以直接监听 val allUsers: Flow<List<User>> = userDao.getAllUsers() // 封装插入操作,有需要的话这里可以加远程请求逻辑(比如先调API再存本地) suspend fun insertUser(user: User) { userDao.insertUser(user) } suspend fun deleteUser(user: User) { userDao.deleteUser(user) } }
3. ViewModel层:用ViewModelScope管理Coroutine,安全收集Flow
ViewModel用自带的viewModelScope启动Coroutine(自动在ViewModel销毁时取消,避免内存泄漏),用repeatOnLifecycle确保只在UI可见时收集Flow。
先添加必要的依赖(直接复制到build.gradle):
// Lifecycle库,用于处理生命周期安全的Flow收集 implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
然后写ViewModel代码:
class UserViewModel(private val repository: UserRepository) : ViewModel() { // 用StateFlow暴露给UI(比LiveData更贴合Flow生态) private val _users = MutableStateFlow<List<User>>(emptyList()) val users: StateFlow<List<User>> = _users init { // 监听Repository的Flow,更新StateFlow viewModelScope.launch { // 仅在UI处于STARTED状态时收集,STOPPED时自动取消 repeatOnLifecycle(Lifecycle.State.STARTED) { repository.allUsers.collect { userList -> _users.value = userList } } } } // 处理UI触发的插入事件 fun insertUser(user: User) { viewModelScope.launch { repository.insertUser(user) } } // 处理UI触发的删除事件 fun deleteUser(user: User) { viewModelScope.launch { repository.deleteUser(user) } } }
4. UI层:安全收集Flow(两种场景示例)
Jetpack Compose场景
@Composable fun UserScreen(viewModel: UserViewModel = viewModel()) { // 自动处理生命周期的Flow收集 val users by viewModel.users.collectAsStateWithLifecycle() LazyColumn { items(users) { user -> UserItem(user, onDeleteClick = { viewModel.deleteUser(user) }) } } Button(onClick = { viewModel.insertUser(User(1, "测试用户", "test@example.com")) }) { Text("添加用户") } }
传统View(Activity/Fragment)场景
class UserActivity : AppCompatActivity() { private lateinit var viewModel: UserViewModel private lateinit var adapter: UserAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_user) adapter = UserAdapter() rv_users.adapter = adapter viewModel = ViewModelProvider(this)[UserViewModel::class.java] // 生命周期安全的Flow收集 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.users.collect { userList -> adapter.submitList(userList) } } } btn_add.setOnClickListener { viewModel.insertUser(User(1, "测试用户", "test@example.com")) } } }
核心要点总结
- Repository是必要的:解耦UI与数据层,封装多数据源逻辑,方便单元测试。
- Room+Flow:DAO返回Flow实现数据自动监听,无需手动轮询数据库。
- Coroutines:用
suspend修饰耗时操作,配合viewModelScope/lifecycleScope管理生命周期,避免内存泄漏。 - 生命周期安全:用
repeatOnLifecycle和collectAsStateWithLifecycle确保Flow只在UI可见时收集,节省系统资源。
内容的提问来源于stack exchange,提问作者Sqa
相关产品推荐
相关产品推荐

