Question Details

No question body available.

Tags

android kotlin

Answers (2)

July 18, 2026 Score: 2 Rep: 95,308 Quality: Low Completeness: 20%

You're architecting your code wrong. In your compose code, you shouldn't be reading preferences, getting data from any source, or doing any work other than displaying UI. These things should all be part of your state, and your UI should be driven only by the state.

To answer your question- no, the code outside the onClick is not run when clicked. It is run only when a recompose is needed. Which is only when any state for the composable changes. Instead, you should have somewhere in your ViewModel a StateFlow with the value of the enablement state. You should collectAsState on that variable. Then whenever it changes, your button will be redrawn.

July 18, 2026 Score: 0 Rep: 22,805 Quality: Medium Completeness: 80%

To elaborate on Gabe Sechan's answer, this is how your code could look like when you use a DataStore to persist your preferences.

The important part required from the DataStore is that it must provide the current setting as a Flow, that always emits a new value when the preference is changed. Fortunateley the DataStore natively supports Flows, so it can be as simple as this:

private val Context.dataStore by preferencesDataStore("settings")
private val enabledKey = booleanPreferencesKey("enabled")

class SettingsDataStoreManager(context: Context) { private val dataStore = context.dataStore

val enabled: Flow = dataStore.data .map { it[enabledKey] ?: false }

suspend fun setEnabled(enabled: Boolean) { dataStore.edit { it[enabledKey] = enabled } } }

Then you can have a view model pass this Flow through to your UI, using stateIn() to convert it to a StateFlow:

class MyViewModel(val applicationContext: Context) : ViewModel() {
    private val settings = SettingsDataStoreManager(applicationContext)

val enabled = settings.enabled.stateIn( scope = viewModelScope, initialValue = false, started = SharingStarted.WhileSubscribed(5.seconds), )

fun setEnabled(enabled: Boolean) { viewModelScope.launch { settings.setEnabled(enabled) } } }

Any in your composable you can finally collect this Flow, converting it into a Compose State:

@Composable
fun MyButton(modifier: Modifier = Modifier) {
    val context = LocalContext.current
    val viewModel = viewModel { MyViewModel(context.applicationContext) }

val isEnabled by viewModel.enabled.collectAsStateWithLifecycle() val color = if (!isEnabled) ButtonGreen else ButtonRed

Button( onClick = { viewModel.setEnabled(!isEnabled) }, colors = ButtonDefaults.buttonColors(containerColor = color), ) { Text("Toggle") } }

That's it. Whenever the button is clicked, the preference in the DataStore is toggled. In response to this, the Flow emits this new, changed value and your composable - by proxy of the view model - also immediately receives this value as a changed State.

And since state changes trigger a recomposition, the color is recalculated and the Button repainted with that color.


To learn more about the architectural patterns involved see Unidirectional data flow (UDP) and this explanation for why you should extract all data access into a separate Data Layer.