Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

558
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda