遵循谷歌最新架构的MVVM:如何从Repository通知ViewModel更新数据
嘿,这个问题其实不用依赖RxJava就能完美解决——Android Jetpack最新的架构组件已经给我们准备好了原生的观察者方案,不管是LiveData还是Flow都能搞定,我给你拆解下具体怎么做:
Repository作为数据层,只需要对外暴露可观察的数据流,ViewModel订阅这个数据流,一旦Repository拿到新的User数据,数据流就会自动通知ViewModel,ViewModel再更新自己的LiveData/Flow给Fragment更新UI,完全贴合谷歌的MVVM架构指南。
方案1:用LiveData(适合Java/Kotlin混合项目,或习惯LiveData的场景)
步骤1:改造Repository暴露LiveData
在Repository里维护一个私有MutableLiveData,当API调用拿到User数据后更新它,对外暴露不可变的LiveData避免外部随意修改:
class Repository { // 私有可变LiveData,仅Repository内部可以修改 private val _userLiveData = MutableLiveData<User?>() // 对外暴露不可变的LiveData val userLiveData: LiveData<User?> = _userLiveData fun fetchUserFromApi() { // 模拟API请求(实际应该用协程或OkHttp异步调用) CoroutineScope(Dispatchers.IO).launch { val user = apiService.getUser() // 切换回主线程更新LiveData(LiveData.postValue也可以自动切线程) withContext(Dispatchers.Main) { _userLiveData.value = user } } } }
步骤2:ViewModel观察Repository的LiveData
在MainViewModel里,直接观察Repository的LiveData,或者用Transformations做转换后再暴露给Fragment:
class MainViewModel(private val repository: Repository) : ViewModel() { // 可以直接把Repository的LiveData转成自己的UI状态LiveData val userUiState: LiveData<User?> = repository.userLiveData // 或者如果需要额外处理数据,比如过滤、转换 val processedUser: LiveData<String> = Transformations.map(repository.userLiveData) { user -> user?.name ?: "Unknown User" } }
方案2:用Flow(Jetpack推荐的现代响应式方案,Kotlin优先)
Flow是Kotlin协程的一部分,比LiveData更灵活,支持更多操作符,而且天然支持协程,是谷歌现在主推的响应式数据流方案。
步骤1:Repository中用StateFlow/SharedFlow
StateFlow适合持有单一状态的数据源(比如当前的User对象),会保留最新值,新订阅者会立即收到最新值SharedFlow适合发送事件流(比如一次性的通知),不会保留历史值
这里我们用StateFlow来持有User数据:
class Repository { // 私有MutableStateFlow,初始值可以设为null或默认User private val _userFlow = MutableStateFlow<User?>(null) // 对外暴露不可变的StateFlow val userFlow: StateFlow<User?> = _userFlow fun fetchUserFromApi() { // 用协程发起API请求,推荐用Repository自己的CoroutineScope,或者依赖注入的Scope CoroutineScope(Dispatchers.IO).launch { val user = apiService.getUser() // 更新StateFlow的值,自动通知所有订阅者 _userFlow.value = user } } }
步骤2:ViewModel收集Flow并更新UI状态
在ViewModel里,用viewModelScope来收集Flow(这个Scope会在ViewModel销毁时自动取消,避免内存泄漏):
class MainViewModel(private val repository: Repository) : ViewModel() { // 方案A:直接把StateFlow转成LiveData给Fragment观察 val userLiveData: LiveData<User?> = repository.userFlow.asLiveData() // 方案B:自己收集Flow,更新内部的MutableLiveData(适合需要额外处理的场景) private val _user = MutableLiveData<User?>() val user: LiveData<User?> = _user init { // 用viewModelScope收集Flow,自动管理生命周期 viewModelScope.launch { repository.userFlow.collect { user -> _user.value = user } } } // 方案C:直接暴露StateFlow给Fragment,Fragment用lifecycleScope收集 val userStateFlow: StateFlow<User?> = repository.userFlow }
如果Fragment直接观察StateFlow,代码大概是这样:
class MainFragment : Fragment() { private val viewModel: MainViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 用lifecycleScope收集Flow,自动在Fragment销毁时取消 viewLifecycleOwner.lifecycleScope.launch { viewModel.userStateFlow.collect { user -> // 更新UI user?.let { updateUserUi(it) } } } } }
要不要用RxJava?
完全没必要!原因有这几点:
- Jetpack原生支持:LiveData和Flow都是Android架构组件的一部分,不需要额外引入RxJava的依赖,减少包体积
- 生命周期安全:LiveData自动感知Fragment/Activity的生命周期,Flow配合
viewModelScope/lifecycleScope也能自动管理订阅,避免内存泄漏,比RxJava需要手动管理Disposable更省心 - 贴合Kotlin生态:Flow是Kotlin协程的一部分,和现代Android开发的协程、ViewModel、Lifecycle等组件无缝集成,代码更简洁
当然,如果你的项目已经大面积使用RxJava,那也可以用RxJava的Observable/Single来实现,但这不是最优解,谷歌最新的架构指南更推荐用Flow。
总结
你只需要让Repository暴露LiveData或Flow,ViewModel订阅这个数据流,就能实现Repository到ViewModel的自动通知,完全符合谷歌最新的MVVM架构规范,不需要依赖RxJava。这种方案不仅简洁,还能保证生命周期安全,是当前Android开发的最佳实践。
内容的提问来源于stack exchange,提问作者Uday

