Interview QuestionPractical QuestionFollow-up Questions

Collecting Flows Safely in Composable Functions

skydovesJaewoong Eum (skydoves)||7 min read

Collecting Flows Safely in Composable Functions

Collecting Flow inside Composable functions is a common pattern for handling UI state and reacting to data changes. If not managed properly, it can lead to memory leaks, unnecessary background work, or excessive recompositions. Jetpack Compose provides two primary APIs for converting flows into observable state: collectAsState and collectAsStateWithLifecycle. Understanding how each one interacts with the composition lifecycle and the Android activity lifecycle is essential for building efficient and leak free UIs. By the end of this lesson, you will be able to:

  • Explain how collectAsState converts a Flow into a Compose State object.
  • Describe why collectAsState does not pause collection when the UI is in the background.
  • Explain how collectAsStateWithLifecycle ties flow collection to the Android lifecycle.
  • Choose the correct API based on whether the collection should be lifecycle aware.

Using collectAsState

collectAsState collects a Flow and converts it into a State object that triggers recomposition whenever the flow emits a new value. The collection starts when the composable enters the composition and stops when it leaves.

@Composable
fun UserProfileScreen(viewModel: UserViewModel) {
    val userName by viewModel.userNameFlow.collectAsState(initial = "")

    Column {
        Text(text = "User: $userName")
    }
}

The userNameFlow is collected as a state, and the UI recomposes whenever a new value is emitted. However, collectAsState does not respect the Android lifecycle. If the composable remains in memory but is not actively displayed, such as when the user navigates away, the flow continues to be collected. This can result in unnecessary resource usage, especially for flows backed by network calls or sensor data.

Using collectAsStateWithLifecycle

collectAsStateWithLifecycle is the lifecycle aware alternative. It pauses flow collection when the host activity or fragment moves to the background and resumes collection when it returns to the foreground.

@Composable
fun UserProfileScreen(viewModel: UserViewModel) {
    val userName by viewModel.userNameFlow
        .collectAsStateWithLifecycle(initialValue = "")

    Column {
        Text(text = "User: $userName")
    }
}

This API observes the Lifecycle of the host and only collects when the lifecycle is at least in the STARTED state by default. When the UI moves to the background, collection is automatically suspended. When it returns to the foreground, collection resumes from where the flow left off.

This interview continues for subscribers

Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.

Become a Sponsor