I save the state of an options menu checkbox item (checked/unchecked) in Jetpack DataStore:
override fun onOptionsItemSelected(item: MenuItem) =
when (item.itemId) {
R.id.action_hide_completed_tasks -> {
item.isChecked = !item.isChecked
viewModel.hideCompleted(item.isChecked)
true
}
else -> super.onOptionsItemSelected(item)
}
which calls through to this method:
suspend fun updateHideCompleted(hideCompleted: Boolean) {
dataStore.edit { preferences ->
preferences[PreferencesKeys.HIDE_COMPLETED] = hideCompleted
}
}
Now I want to restore this checkbox state when my fragment comes onto the screen. But since Jetpack DataStore provides the user preferences in form of a Flow
, this feels a bit hacky. I collect from this Flow
in onPrepareOptionsMenu
and use the take(1)
operator to only do it once, because after that I don't need to update the checkbox from the preferences anymore, the state automatically changes when I click the options menu item:
override fun onPrepareOptionsMenu(menu: Menu) {
lifecycleScope.launch {
viewModel.preferencesFlow
.take(1) // I want this to update only when the fragment comes onto the screen, afterward it's unnecessary
.collect {
menu.findItem(R.id.action_hide_completed_tasks).isChecked = it.hideCompleted
}
}
}
Is this the correct approach? It feels a bit hacky. Will the asynchronicity cause problems in certain cases?
I believe the proper way to do it is using the Flow<T>.first()
operator.
override fun onPrepareOptionsMenu(menu: Menu) {
lifecycleScope.launch {
val value = viewModel.preferencesFlow.first()
menu.findItem(R.id.action_hide_completed_tasks).isChecked = value.hideCompleted
}
}