collectAsStateWithLifecycle in Jetpack Compose: Why It Replaced collectAsState

collectAsStateWithLifecycle() is the recommended way to read a StateFlow (or any Flow) inside a composable. It replaced the older collectAsState() in most Android codebases for one specific reason: lifecycle awareness.

The Problem with collectAsState

collectAsState() collects a Flow for as long as the composable is part of the Composition. That’s not quite the same as “the screen is visible.” If the user backgrounds the app or the screen is covered by another one, the Composition can still be active, which means the collection keeps running, and any update to the flow still triggers work — wasted CPU and, for a flow backed by a network subscription, wasted data.

What collectAsStateWithLifecycle Does Differently

It ties collection to the Lifecycle of the surrounding LifecycleOwner (typically the Activity or Fragment). By default it collects only while the lifecycle is at least STARTED — it automatically stops when the app is backgrounded and resumes when it’s foregrounded again, rather than collecting continuously regardless of visibility.

class ProductsViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(ProductsUiState())
    val uiState: StateFlow<ProductsUiState> = _uiState.asStateFlow()
}

@Composable
fun ProductsScreen(viewModel: ProductsViewModel) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    ProductList(products = uiState.products)
}

The call site looks almost identical to collectAsState() — the difference is entirely in the lifecycle behavior underneath.

Setup

collectAsStateWithLifecycle lives in a separate artifact and needs its own dependency:

implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.0")

(Check the current version on the AndroidX release notes — this library is updated independently of Compose itself.)

When collectAsState Is Still Fine

In Compose Multiplatform code that targets non-Android platforms, collectAsStateWithLifecycle isn’t available, since the Android Lifecycle concept doesn’t exist there — plain collectAsState() is what you’ll use in shared code. For Android-only screens, though, prefer collectAsStateWithLifecycle; it’s a drop-in improvement with no real downside.