'How to observe ViewModel LiveData changes from Compose state holder class?

I am following the Android Developers Managing State in Compose guide. https://developer.android.com/jetpack/compose/state#managing-state

I have implemented my own state holder which takes the viewModel as parameter as per diagram below. Inside the state holder I have State objects like mutableStateOf() which trigger re-composition.

The issue I am having is how to have MyStateHolder observe changes to LiveData in MyViewModel. As MyStateHolder is a POJO, I cannot use features such as observeAsState().

It seems odd that google recommend this approach but provide no out of the box way to do this.

How can I observe changes from viewModel in state holder? Am I missing something?

Jetpack Compose Managing State Architecture

class MyStateHolder(
    private val viewModel: MyViewModel,
) {
    //initialise state variables and observe _portfolioData
    var portfolioDataMap = mutableStateMapOf<String, PortfolioDataModel>().apply {
        putAll(viewModel.portfolioData.value!!)
        viewModel.portfolioData.observeAsState() /*error here: cannot observeAsState in POJO*/
    }
}

class MyViewModel : ViewModel() {
    private val _portfolioData: MutableLiveData<Map<String, PortfolioDataModel>> =
        MutableLiveData()
    val portfolioData: LiveData<Map<String, PortfolioDataModel>>
        get() = _portfolioData

    fun setStateEvent(mainStateEvent: MainStateEvent<String>) {
        //send events to update _portfolioData
    }
}


Solution 1:[1]

Observing life model requires a lifecycle owner. You can add this parameter to your state holder:

class MyStateHolder(
    private val lifecycleOwner: LifecycleOwner,
    private val viewModel: MyViewModel,
) {
    //initialise state variables and observe _portfolioData
    var portfolioDataMap = mutableStateMapOf<String, PortfolioDataModel>().apply {
        putAll(viewModel.portfolioData.value!!)
    }

    init {
        viewModel.portfolioData.observe(lifecycleOwner) {
            portfolioDataMap.clear()
            portfolioDataMap.putAll(it)
        }
    }
}

And during initialization you can pass it from LocalLifecycleOwner.current, basically like this:

@Composable
fun rememberMyStateHolder() : MyStateHolder {
    val lifecycleOwner = LocalLifecycleOwner.current
    val viewModel = viewModel<MyViewModel>()
    // consider using rememberSaveable instead of remember with a custom saver
    // in case of configuration change, e.g. screen rotation
    return remember(lifecycleOwner, viewModel) {
        MyStateHolder(lifecycleOwner, viewModel)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Pylyp Dukhov