Reputation: 11
I read that mutable objects are not observable, thus recomposition won't happen even if a field inside a mutable object had been reassigned. Because of this I can't figure out how to implement a specific task, and I'd appreciate your help.
Basically, I want the user to be able to create his own custom salad. He is displayed with the different ingredients as buttons, and when clicked they are added to the salad object. There are a few different ingredients categories (and prices), and additionally, Salad has more properties such as size, dressing, takeout and some functionality. so all in all, salad should really be a plain old object, and not some sort of list.
My problem is that I want to recompose some of the UI as the user picks his ingredients (changing order's picture, marking the ingredient, unmarking some other ingredients if there is a conflict with the new one, etc.), but recompose won't happen because the changes happen inside a mutable object so I can't observe these changes.
So in short, how can I pull off updating the Jetpack Compose based UI when changes are made to the salad object's attributes?
Upvotes: 1
Views: 3273
Reputation: 1674
In order to reflect attribute changes in Compose UI, the attribute must be a mutable state.
A combination of data classes and classes with MutableState
variables can be used to capture state of UI.
Below is a sample of how it can be done.
class Salad(size: Int, dressing: String, priIng: Ingredient) {
// for primitive properties use MutableState, using delegate here ("by" syntax) can be handy
var size by mutableStateOf(size)
var dressing by mutableStateOf(dressing)
var primaryIngredient by mutableStateOf(priIng)
// for mutable lists use a SnapshotStateList
val ingredients = mutableStateListOf<Ingredient>()
// or use SnapshotStateMap for mutable map structures in compose UI
val ingredientsWithQuantity = mutableStateMapOf<Ingredient, Int>()
}
// immutable data
data class Ingredient(
val name: String,
val calories: Int
)
Updating attributes of salad object will now trigger UI updates as well as they are backed by corresponding mutable states.
var salad = remember { Salad(2, "Dressing", Ingredient("apple", 1)) }
// update any property as you do with normal objects from any event like user click action
salad.size += 1
salad.primaryIngredient = salad.primaryIngredient.copy(name="orange")
To modify primary constructor member of immutable data class, copy function can be used.
var ing by remember { mutableStateOf(Ingredient("apple", 20)) }
// to update one or more properties use copy function for data class
ing = ing.copy(calories = 100)
Upvotes: 1