Which one is better to use in ViewModel StateFlow or Compose State

Which one is better to use in ViewModel StateFlow or Compose State


If you already work with compose you face this challenge

Which one we should use in ViewModel? StateFlow or compose State

As you know HotFlow and compose State(mutableStateOf()) are Reactive which means the program reacts to data or event changes instead of requesting information about changes.

When we call stateFlow from ViewModel in a compose function we use the collectAsStateWithLifecycle extension function.

How does it work internally?

collectAsStateWithLifecycle is a composable function that collects values from a flow and represents the latest value as Compose State in a lifecycle-aware manner. Every time a new flow emission occurs, the value of this State object updates.

By default, collectAsStateWithLifecycle uses Lifecycle.State.STARTED to start and stop collecting values from the flow. This occurs when the Lifecycle moves in and out of the target state.

You can move the lifecycle with the minActiveState parameter

@Composable
fun <T> StateFlow<T>.collectAsStateWithLifecycle(
   lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
   minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
   context: CoroutineContext = EmptyCoroutineContext
): State<T> = collectAsStateWithLifecycle(
      initialValue = this.value,
      lifecycle = lifecycleOwner.lifecycle,
      minActiveState = minActiveState,
      context = context
   )        

collectAsStateWithLifecycle uses produceState to convert flow to a compose state

@Composable
fun <T> Flow<T>.collectAsStateWithLifecycle(
   initialValue: T,
   lifecycle: Lifecycle,
   minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
   context: CoroutineContext = EmptyCoroutineContext
): State<T> {
   return produceState(initialValue, this, lifecycle, minActiveState, context) {
      lifecycle.repeatOnLifecycle(minActiveState) {
         if (context == EmptyCoroutineContext) {
            [email protected] { [email protected] = it }
         } else withContext(context) {
            [email protected] { [email protected] = it }
         }
      }
   }
}  }
}        

Now as we know when a user navigates another screen flow stops collecting because of the use lifecycle internally.


Why do we need to use flow instead of compose state inside ViewModel :

  1. ViewModel should be independent of UI. It is not a good choice to use Compose in VM.
  2. MutableStateFlowis multi-thread safe. You can use MutableStateFlow.update{} to update it in any thread or any coroutine context. However,mutableStateOf is not.

Now My question is :

What happens about the Lifecycle when we use compose State ( mutableStateOf() ) in ViewModel?

First, we should check the viewModel lifecycle in the compose

So as the document says: To use a ViewModel in Compose, you can?pass the lifecycleOwner parameter to the ViewModel constructor. The lifecycleOwner will keep track of the lifecycle of the composable and will ensure that the ViewModel is only active when the composable is visible.

For instance :

You can use?navigation, which is perfect for your needs, each route has its own view model scope, which is destroyed as soon as the route is removed from the navigation back stack.

Or you can use DisposableEffect for free viewModel when the screen isn't active anymore...

So if you use compose State in ViewModel don't forget to consider the state lifecycle

Tell me about your idea or your experiences in comment

Konstantin Adamov

Principal Software Engineer at Advanced Bionics R&D-Software Engineering

5 个月

While the general principle of ViewModel independence from UI is sound, in Compose's reactive paradigm, ViewModels are designed to directly drive UI state. Using State with a private setter offers a more streamlined approach than Flow. Flow requires additional code within Composable components, such as observerAsState, which can make the UI logic less declarative and more procedural. Of course you can combine these two, but Flow is more suitable for Services and Repositories which ViewModel can observe for changes and reflect them for UI

回复
?brahim Hakk? Ero?lu

Wireline Log Engineer

1 年

Thank you for sharing

Arda K.

Senior Android Engineer @Nesine

1 年

Thanks for your effort. It also provides usage advantages such as "map, filter, flatmaplatetest, etc." in the downstream process.

Hasan Zolfagharipour

Android Developer | Kotlin, Java | Compose | Swift UI

1 年

Great article ? Thank you for sharing ?? ? While Compose has many advantages,?I believe there could be more reasons to use the ViewModel as Flow-based. This approach also would allow us to combine different flows and leverage the power of flow operators more effectively.

要查看或添加评论,请登录

Mozhdeh Nouri Sarani的更多文章

社区洞察

其他会员也浏览了