En nuestra aplicación de Android, queremos presentar Compose en una pantalla de depuración simple, donde podemos habilitar/deshabilitar SharedPreferences. Estoy tratando de hacer que funcione usando la interfaz MutableState de Compose, pero no funciona como creo que lo hace. Mi plan es usar MutableState temporalmente para establecer un valor booleano en SharedPreferences (antes de migrar a DataStore más adelante).
Esto es lo que tenía en mente:
private class MyOwnState(startWith: Boolean) : MutableState<Boolean> { override var value: Boolean = startWith override fun component1(): Boolean = value override fun component2(): (Boolean) -> Unit = { value = it } } // then, in composable: var value by remember { MyOwnState(false) } Por supuesto, en la vida real sobrescribiría el getter+setter del value , pero este ejemplo es suficiente, porque no funciona. El cambio de estado no se propaga y la interfaz de usuario no se actualiza.
Para ilustrar esto, junté los fragmentos de código by remember { mutableStateOf(false) } y by remember { MyOwnState(false) } . El primero funciona (el interruptor se actualiza), el segundo no.
Código completo:
@Composable fun SomeStateExamples() { Column { SwitchWorks() SwitchDoesNotWork() } } @Composable fun SwitchWorks() { var value by remember { mutableStateOf(false) } Switch(checked = value, onCheckedChange = { value = it }) } @Composable fun SwitchDoesNotWork() { var value by remember { MyOwnState(false) } Switch(checked = value, onCheckedChange = { value = it }) } private class MyOwnState(startWith: Boolean) : MutableState<Boolean> { override var value: Boolean = startWith override fun component1(): Boolean = value override fun component2(): (Boolean) -> Unit = { value = it } }El primer interruptor es conmutable, el segundo no lo es:
¿Qué me estoy perdiendo? La interfaz de MutableState es bastante simple y estable, y no encontré ningún método adicional (también conocido como invalidar, notificar a los oyentes, ...) que deba llamar.
¡Gracias por tu ayuda! 🙏
Agregando a la respuesta de Johan, parece que también necesita implementar StateObject para obtener el valor y actualizar el sistema de instantáneas. Echando un vistazo a SnapshotMutableStateImpl
override var value: T get() = next.readable(this).value set(value) = next.withCurrent { if (!policy.equivalent(it.value, value)) { next.overwritable(this, it) { this.value = value } } } private var next: StateStateRecord<T> = StateStateRecord(value) override val firstStateRecord: StateRecord get() = next Verá que usar StateObject lo hace trabajar con StateRecord s donde almacena el valor actualizable, lo lee y lo actualiza.
No es una respuesta directamente, pero al ver cómo funciona mutableStateOf , también está llamando a createSnapshotMutableState(value, policy) detrás de escena.
Por lo tanto, no creo que simplemente heredar MutableState y cambiar eso haga que Compose inicie una recomposición y, por lo tanto, actualice la interfaz de usuario.
Probablemente intentaría pasar el estado de la interfaz de usuario desde el exterior como un modelo con ViewModel o LiveData y mutar los datos del modelo.
En su clase MyOwnState , debe implementar un valor mutableState privado como este:
private class MyOwnState(startWith: Boolean) : MutableState<Boolean> { private var _value by mutableStateOf(startWith) override var value: Boolean = startWith get() = _value set(value) { _value = value field = value } override fun component1(): Boolean = value override fun component2(): (Boolean) -> Unit = { value = it } } Cuando intente cambiar el value dentro de componible, la composición se recompondrá porque también cambió MutableState _value . Obtenga más información sobre cómo funciona el estado en Jetpack Compose aquí .