Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

559
Vistas
Jetpack Compose State: Modificar propiedad de clase

Los dos ejemplos siguientes simplemente agregan una 'a' a un valor predeterminado dado. El compose_version utilizado es 1.0.0-alpha03 que es el último a la fecha (que yo sepa).

Este ejemplo es más similar a la mayoría de los ejemplos que he encontrado durante mi investigación.

Ejemplo 1

 @Composable fun MyScreen() { val (name, setName) = remember { mutableStateOf("Ma") } Column { Text(text = name) // 'Ma' Button(onClick = { setName(name + "a") // change it to 'Maa' }) { Text(text = "Add an 'a'") } } }

Sin embargo, esto no siempre es práctico. Digamos, por ejemplo, que los datos eran más complejos que un solo campo. Una clase, por ejemplo, o incluso una data class Room .

Ejemplo 2

 // the class to be modified class MyThing(var name: String = "Ma"); @Composable fun MyScreen() { val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) } Column { Text(text = myThing.name) // 'Ma' Button(onClick = { var nextMyThing = myThing nextMyThing.name += "a" // change it to 'Maa' setMyThing(nextMyThing) }) { Text(text = "Add an 'a'") } } }

Por supuesto, el Ejemplo 1 funciona, pero el Ejemplo 2 no. ¿Se trata de un simple error de mi parte, o me estoy perdiendo el panorama general sobre cómo debo modificar esta instancia de clase?

EDITAR:

He encontrado una manera de hacer que esto funcione, pero parece ineficiente. Sin embargo, se alinea con la forma en que React administra el estado, por lo que tal vez sea la forma correcta de hacerlo.

El problema en el Ejemplo 2 claramente es que myNextThing no es una copia del myThing original, sino una referencia a él. Al igual que React, Jetpack Compose parece querer un objeto completamente nuevo al modificar el estado. Esto se puede hacer de una de dos maneras:

  1. Crear una nueva instancia de la clase MyThing , cambiar lo que se necesita cambiar y luego llamar a setMyThing() con la nueva instancia de clase
  2. Cambiando class MyThing a data class MyThing y usando la función copy() para crear una nueva instancia con las mismas propiedades. Luego, cambie la propiedad deseada y llame a setMyThing() . Esta es la mejor manera en el contexto de mi pregunta dado que declaré explícitamente que me gustaría usar esto para modificar los datos en una data class determinada utilizada por Android Room.

Ejemplo 3 (funcional)

 // the class to be modified data class MyThing(var name: String = "Ma"); @Composable fun MyScreen() { val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) } Column { Text(text = myThing.name) // 'Ma' Button(onClick = { var nextMyThing = myThing.copy() // make a copy instead of a reference nextMyThing.name += "a" // change it to 'Maa' setMyThing(nextMyThing) }) { Text(text = "Add an 'a'") } } }
over 4 years ago · Hanz Gallego
3 Respuestas
Responde la pregunta

0

De hecho, me parece que la mejor manera de hacerlo es copy() una data class .

Un ejemplo completo y útil usando la reflexión (para permitir la modificación de mis diferentes tipos de propiedades podría verse así:

 // the class to be modified data class MyThing(var name: String = "Ma", var age: Int = 0); @Composable fun MyScreen() { val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) } // allow the `onChange()` to handle any property of the class fun <T> onChange(field: KMutableProperty1<MyThing, T>, value: T) { // copy the class instance val next = myThing.copy() // modify the specified class property on the copy field.set(next, value) // update the state with the new instance of the class setMyThing(next) } Column { Text(text = myThing.name) // button to add "a" to the end of the name Button(onClick = { onChange(MyThing::name, myThing.name + "a") }) { Text(text = "Add an 'a'") } // button to increment the new "age" field by 1 Button(onClick = { onChange(MyThing::age, myThing.age + 1) }) { Text(text = "Increment age") } } }

Si bien puede ser que instanciar una copia de la clase en estado cada vez que se hace clic en el botón (o se presiona el teclado en un caso de uso real con un TextField en lugar de un botón) puede ser un poco inútil para clases más grandes, en general, parece que el marco Compose preferiría este enfoque. Como se indicó, esto se ajusta a la forma en que React hace las cosas: el estado nunca se modifica ni se agrega, siempre se reemplaza por completo.

Sin embargo, un enfoque alternativo sería muy bienvenido.

over 4 years ago · Hanz Gallego Denunciar

0

De hecho, me parece que la mejor manera de hacerlo es copiar () una clase de datos.

En el caso específico de usar remember() de una data class personalizada, probablemente sea la mejor opción, aunque se puede hacer de manera más concisa usando parámetros con nombre en la función copy() :

 // the class to be modified data class MyThing(var name: String = "Ma", var age: Int = 0) @Composable fun MyScreen() { val (myThing, myThingSetter) = remember { mutableStateOf(MyThing()) } Column { Text(text = myThing.name) // button to add "a" to the end of the name Button(onClick = { myThingSetter(myThing.copy(name = myThing.name + "a")) }) { Text(text = "Add an 'a'") } // button to increment the new "age" field by 1 Button(onClick = { myThingSetter(myThing.copy(age = myThing.age + 1)) }) { Text(text = "Increment age") } } }

Sin embargo, seguiremos actualizando los modelos de vista y observando los resultados de ellos ( LiveData , StateFlow , RxJava Observable , etc.). Espero que remember { mutableStateOf() } se usará localmente para los datos que aún no están listos para enviarse al modelo de vista pero que necesitan múltiples bits de entrada del usuario y, por lo tanto, deben representarse como estado. Si siente o no que necesita una data class para eso o no, depende de usted.

¿Se trata de un simple error de mi parte, o me estoy perdiendo el panorama general sobre cómo debo modificar esta instancia de clase?

Compose no tiene forma de saber que el objeto cambió, por lo que no sabe que se necesita una recomposición.

En general, Compose está diseñado para reaccionar a flujos de datos inmutables. remember { mutableStateOf() } crea una transmisión local.

Sin embargo, un enfoque alternativo sería muy bienvenido.

No estás limitado a un solo remember :

 @Composable fun MyScreen() { val name = remember { mutableStateOf("Ma") } val age = remember { mutableStateOf(0) } Column { Text(text = name.value) // button to add "a" to the end of the name Button(onClick = { name.value = name.value + "a"}) { Text(text = "Add an 'a'") } // button to increment the new "age" field by 1 Button(onClick = { age.value = age.value + 1 }) { Text(text = "Increment age") } } }
over 4 years ago · Hanz Gallego Denunciar

0

Ok, para cualquiera que se pregunte sobre esto, hay una manera más fácil de resolver este problema. Cuando defines tu propiedad de estado mutable como esta:

 //There is a second paremeter wich defines the policy of the changes on de state if you //set this value to neverEqualPolicy() you can make changes and then just set the value class Vm : ViewModel() { val dummy = mutableStateOf(value = Dummy(), policy= neverEqualPolicy()) //Update the value like this fun update(){ dummy.value.property = "New value" //Here is the key since it has the never equal policy it will treat them as different no matter the changes dummy.value = dummy.value } }

Para obtener más información sobre las políticas disponibles: https://developer.android.com/reference/kotlin/androidx/compose/runtime/SnapshotMutationPolicy

over 4 years ago · Hanz Gallego Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda