Jetpack Compose with Kotlin Flow: The Delegation Advantage!

Raphael Cohen
2 min readJun 13, 2024

--

property delegation visual in the context of trivia app’s radio buttons.

In Kotlin the by keyword is used for property delegation, which automates the getter & setter functions for a property. When you use by tied to Compose’s collectAsState(), the delegate allows the UI to observe state changes & update without needing to manually manage the value property of the state. This makes code more dev friendly (readable) and idiomatic 👍🏾

// composable
val enabled by viewModel.enableRadioButtons.collectAsState()

// viewModel
private val _enable = MutableStateFlow(true)
val enableRadioButtons: StateFlow<Boolean> = _enable.asStateFlow()

fun enableRadioButtons(isEnabled: Boolean) {
flow<Boolean> {
_enableRadioButtons.emit(isEnabled)
}.catch {
_enableRadioButtons.emit(true)
}.launchIn(viewModelScope)
}

How does enabled talk to the Composable radio buttons?

IconToggleButton(
checked = selectedAnswer.value == answer,
enabled = enabled,
onCheckedChange = {
viewModel.enableRadioButtons(false)
selectedAnswer.value = answer
},
modifier = Modifier
.size(dimensionResource(R.dimen.dimen_xxxlarge_26))
.padding(end = dimensionResource(R.dimen.dimen_medium_x))
) {
TriviaRadioButton(painter, color)
}

// Some context, when you select a radio button you choose and answer
// and can not choose again if wrong, so disable buttons reactively.

The line val enabled by viewModel.enableRadioButtons.collectAsState() is used to observe changes from the viewModel and update the enabled state of the IconToggleButton in real-time using Flows. This ensures that the IconToggleButton reflects the current state of interactivity as dictated by the viewModel, allowing for a responsive & dynamic user experience.

— Assignment vs. Delegation —

// assigning enabled to state
val enabled = viewModel.enableRadioButton.collectAsState()

On the other hand, assigning the value directly without delegation for exampleval enabled = viewModel.enableRadioButtons.collectAsState(), you’re not observing the changes of the Flow. Instead, you’re assigning the State object returned by collectAsState() to enabled, which won’t automatically update the Composable when the Flow emits new values.

In Jetpack Compose, developers have the option to choose between direct assignment or utilizing the property delegation sugar. Ultimately it comes down to promoting clean architecture that is reactive, efficient and idiomatic:)

Try the trivia feature out in Jetpack Compose on Google Play 🥳🚀 https://play.google.com/store/apps/details?id=com.brickyard.nhl

🗣️: reach out on X or Insta

Best,
RC

--

--