androidkotlinandroid-jetpack-composeandroid-viewmodeldagger-hilt

Have the remember constructs in Android jetpack compose to be used only in the context of a composable function?


My question is about the remember constructs used in jetpack compose and kotlin. As you most probably already know these are the ones I am reffering to:

var first = remember { mutableStateOf(true) } 
var second by remember { mutableStateOf(true) }

Now my question is if they can only be used in the context of a Composable function? My guess is that the answer is yes. To give you a little more context, I am currently working on a project and I've done the ui layer and the navigation part and now I am trying to implement the ViewModel interface. Till now, I used the two above for almost every ui logic inside the screen composables. But now, I noticed that I cannot use them anymore in the data classes of type UIState. The solution was to simply declare them as mutableState. Is this the only equivalent way of replacing them when switching to the hilt/viewModel/dependency injection part?

I know it might be obvious, but I thought it would be more clarifying. Thanks in advance!


Solution

  • The various remember functions are all annotated with @Composable. That makes them composable functions themselves, and that means that they must be called from another composable function. You can easily verify that if you actually try to call them from a a non-composable function. You'll get this error:

    @Composable invocations can only happen from the context of a @Composable function

    The remember functions exist to protect your state from being lost on recompositions. Recompositions actually execute the entire function again, so anything that wasn't remembered is lost. Outside of a composable function these functions are useless, even if they could be called. So just remove the remember from anything that you use in your view model.

    That said, if you remembered a MutableState, you should not use that either in your view model. MutableState is also compose-specific. Although not a composable function (so it will not produce compile errors in your view model), it can be tricky to properly use outside of compose code. It will probably work as expected for the most time, but it would be better to use a MutableStateFlow instead, as shown in the Android documentation. Although they share a similar name, they are entirely different: MutableState is from the Android Compose SDK, where MutableStateFlow is integrated into the Kotlin programming language itself. They are conceptionally similar, though: They both encapsulate a value that can be observed for changes. How the observation is done is completely different, though.

    As a rule of thumb: Whenever you want to observe changes over time, use MutableState when in a composable function and use a flow for everything else.