Hi! I'm trying to create a custom `state` (i gues...
# compose
a
Hi! I'm trying to create a custom
state
(i guess) to save a value in preferences, and trigger recomposition when it changes... However, i managed to save the new value, but it is not triggering a recompostion.. what I'm missing? code on thread
Copy code
@Composable
internal fun rememberBooleanPref(key: String, defaultValue: Boolean): MutableState<Boolean> {
    val context = LocalContext.current
    val manager = PreferenceManager.getDefaultSharedPreferences(context)
    return remember {
        booleanPrefState(manager, key, defaultValue)
    }
}
Copy code
internal fun booleanPrefState(
    sharedPreferences: SharedPreferences, key: String, defaultValue: Boolean,
): MutableState<Boolean> = object : MutableState<Boolean> {
    override var value: Boolean
        get() = sharedPreferences.getBoolean(key, defaultValue)
        set(value) {
            sharedPreferences.edit { putBoolean(key, value) }
        }
    override fun component1(): Boolean = value
    override fun component2(): (Boolean) -> Unit {
        return { value = it }
    }
}
j
Move to data store with its Flow APIs + collectAsState
👍 1
a
i want to try it "simplier" by now 😓
r
Copy code
private val preferenceKeyChangedFlow = MutableSharedFlow<String>(extraBufferCapacity = 1)

    private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
        preferenceKeyChangedFlow.tryEmit(key)
    }

fun setup() {        sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
    }

var yourData: Boolean
        get() = sharedPreferences.getBoolean(YOURKEY, false)
        set(value) = sharedPreferences.edit {
            putBoolean(YOURKEY, value)
        }

fun observeYourData(): Flow<Boolean> {
        return preferenceKeyChangedFlow
            // Emit on start so that we always send the initial value
            .onStart { emit(YOURKEY) }
            .filter { it == YOURKEY }
            .map { yourData }
            .distinctUntilChanged()
    }
instead of writing all this like @Javier suggested use datastore which gives you flow + collectAsState
a
buuuuuut, it forces external code to use datastore...
j
Probably I should use an interface for this, so datastore could be a implementation detail that the user havent to know, but I should not avoid using data store, because, at the end, it is shared preferences + flow APIs, so if you use only shared preferences and your own interface, you will have to re-create the flow APIs, and that is directly what data store does.