Search code examples
androidkotlinmvvmandroid-roomkotlin-flow

Which stream should I choose to getting data from the database?


I'd like to ask you about using "hot" Flow streams in the android app.

Let's start with simple, example scenario. We have an app, with Room database, MVVM architecture pattern, and Flow with Coroutines for manipulating data from database.

There are a couple of fragments inside the app. Every fragment have it's own ViewModel, but they have one thing in common - all of them have same, two things from database:

  • List with colors
  • String with user favorite color.

I'd like to ask, if it is a good way to modify Flow from "cold" stream, to "hot", by using .stateIn. Since all of fragments have recalls to the List and String that I've meantioned above.

Does implementing the hot stream with LifeCycle.State.STARTED would be more efficient, than implementing the cold stream? I'm just trying to figure out, which stream should I choose according to the situation.


Solution

  • Really, you almost always want to use a hot Flow on Android if you're not using Compose, because even if data is only used by one Fragment, that Fragment might get recreated during a screen rotation, and it would waste resources to restart the flow from scratch to fetch the same data every time the screen rotates.

    (If you're using Compose, you likely want to disable screen rotation configuration changes in the manifest. But you still might like to use a hot flow for cases like when a user accidentally taps something to go to another screen and then backs up to the original fragment quickly.)

    Does implementing the hot stream with LifeCycle.State.STARTED would be more efficient, than implementing the cold stream?

    I don't know what you mean by implementing a hot stream with a Lifecycle state.

    The common pattern for creating a hot Flow on Android is to use SharingStarted.WhileSubscribed(5000L). This allows the Flow to remain idle when not in use, but avoids restarting it during a screen rotation (which is assumed to take less than 5 seconds). You can probably reduce this number, but I think it's the same window of time Jetpack's LiveData uses.

    Since you have separate ViewModels, but both Fragments want to use the same data, I think it makes sense to use shareIn or stateIn for a property in the shared repository class. This is probably breaking some MVVM "rule" since it's making your repository slightly aware of how your UI is designed. Up to you. The alternative I guess is to do it in a third ViewModel that is used by both of your Fragments.