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

Android MVVM:模型向视图模型传递数据变化及跨VM通知方法

Great questions about Android MVVM—let's break this down with practical examples and best practices!

1. How does the Model pass data changes to the ViewModel in Android MVVM?

In MVVM, the Model handles all data logic (fetching, updating, storing) and communicates changes to ViewModels without any awareness of the UI layer. The most reliable, lifecycle-safe approaches are:

  • LiveData (Legacy but battle-tested)
    The Model holds a MutableLiveData for mutable data, and exposes an immutable LiveData to ViewModels. When the Model updates its data, it calls setValue() (main thread) or postValue() (background thread) on the MutableLiveData, which triggers the ViewModel's observer.

    Example snippet:

    // StockModel.kt
    class StockModel {
        private val _stockPrice = MutableLiveData<Double>()
        val stockPrice: LiveData<Double> = _stockPrice
    
        fun updatePrice(newPrice: Double) {
            _stockPrice.postValue(newPrice) // Notify all observers
        }
    }
    
    // StockViewModel.kt
    class StockViewModel(private val stockModel: StockModel) : ViewModel() {
        init {
            // Observe the LiveData (bind to a LifecycleOwner like Fragment/Activity for safety)
            stockModel.stockPrice.observe(lifecycleOwner) { newPrice ->
                // Handle price change in ViewModel
            }
        }
    }
    
  • StateFlow (Modern, coroutine-based)
    For Kotlin-first projects, StateFlow (part of Kotlin Coroutines) is the preferred choice—it’s flexible, coroutine-native, and works seamlessly with lifecycle-aware collection. The Model holds a MutableStateFlow, exposes a read-only StateFlow, and ViewModels collect the flow within a coroutine scope.

    Example snippet:

    // StockModel.kt
    class StockModel {
        private val _stockPrice = MutableStateFlow(0.0)
        val stockPrice: StateFlow<Double> = _stockPrice
    
        fun updatePrice(newPrice: Double) {
            _stockPrice.value = newPrice // Notify all collectors
        }
    
        // Example of autonomous update (e.g., WebSocket push)
        fun startRealTimeUpdates() {
            CoroutineScope(Dispatchers.IO).launch {
                while (true) {
                    delay(1000)
                    _stockPrice.value = Random.nextDouble(100.0, 200.0)
                }
            }
        }
    }
    
    // StockViewModel.kt
    class StockViewModel(private val stockModel: StockModel) : ViewModel() {
        init {
            viewModelScope.launch {
                // Collect only when UI is active to avoid memory leaks
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    stockModel.stockPrice.collect { newPrice ->
                        // Handle price change in ViewModel
                    }
                }
            }
        }
    }
    
2. How to notify multiple ViewModels (VM1, VM2 in different Activities) when StockModel updates data?

The core solution hinges on sharing the same StockModel instance across all ViewModels, then using the observable patterns above to broadcast changes to all subscribers. Here’s how to implement it:

  1. Make StockModel a shared instance
    Use dependency injection (like Hilt, Dagger, or Koin) to provide a singleton instance of StockModel. This ensures VM1 and VM2 both receive the exact same Model object. For simpler cases, a Kotlin object works, but DI is better for testability and dependency management.

    Example with Hilt:

    @Singleton
    class StockModel @Inject constructor() {
        // Same StateFlow/LiveData setup as above
    }
    
  2. Each ViewModel observes the shared observable
    Since VM1 and VM2 inject the same StockModel instance, they’ll both collect the same StateFlow/LiveData. Whether VM1 triggers an update via stockModel.updatePrice() or the Model updates autonomously (e.g., WebSocket push), all subscribers (VM1, VM2, and any other ViewModels watching the Model) will receive the change instantly.

    Example for VM2:

    class StockViewModel2 @Inject constructor(private val stockModel: StockModel) : ViewModel() {
        init {
            viewModelScope.launch {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    stockModel.stockPrice.collect { newPrice ->
                        // VM2 reacts to the same price change as VM1
                    }
                }
            }
        }
    }
    
  3. Avoid common pitfalls

    • Never use observeForever without unsubscribing—use repeatOnLifecycle for StateFlow or bind to a LifecycleOwner for LiveData to prevent memory leaks.
    • If using a singleton Model, manage background work (like WebSocket connections) carefully (e.g., cancel coroutines when no active subscribers exist to save resources).

内容的提问来源于stack exchange,提问作者candrwow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:52:58