I am experiencing a very strange problem. I'm making a method to handle click events on the screen, as I want to save all the pointers in a map with their id and position, I have a state class in which I have this map and I'm updating it with a method in the ViewModel
data class RandomState(
val touchedPositions: Map<Long, Pair<Float, Float>> = emptyMap(),
)
fun updateTouchedPositions(
touchedPositions: Map < Long, Pair < Float, Float >>
) {
println("Function from viewModel: $touchedPositions")
state = state.copy(
touchedPositions = touchedPositions)
}
.pointerInput(Unit) {
awaitEachGesture {
val positions = mutableMapOf < Long, Pair < Float, Float >> ()
do {
val event = awaitPointerEvent()
val canceled = event.changes.fastAny {
it.isConsumed
}
if (event.type == PointerEventType.Press) {
event.changes.forEach { pointer - >
val id = pointer.id.value
val x = pointer.position.x
val y = pointer.position.y
positions[id] = Pair(x, y)
}
println("Se van a guardar las posiciones: $positions")
viewModel.updateTouchedPositions(positions)
println("Posiciones de dedos en onPress: ${state.touchedPositions}")
}
if (event.type == PointerEventType.Release) {
println("Posiciones de dedos en onRelease: ${state.touchedPositions}")
}
} while (!canceled)
}
}
So I declare in my viewModel my state class which I access in the Composable with a viewModel.state.
// ViewModel class
var state by mutableStateOf(RandomState())
private set
The problem is that although with the debug everything seems to be fine, when I'm in the second print inside the if of the do block, the state.touchedPositions is empty. It's as if the state class is somehow reset to the default state, but I'm not able to know why.
From the code you provided it is unclear what state
is and how it happens to be accessible in pointerInput
, so the following includes a bit of guess work.
pointerInput
is a composable function, and composable functions are usually recomponsed when any state changes that they access. pointerInput
, however, explicitly defines another behavior: Like remember
or LaunchedEffect
, it only recomposes when the key parameter(s) change. Since you provided Unit
as the key, pointerInput
will only be executed once, when the composable enters the composition. It then captures all variables that it needs in a closure. That is like a snapshot of all the objects that the variables currently contain. state
is such a variable who's object will be captured, and that object will be used for everything that happens inside pointerInput
(your log statements).
When the state
variable changes (possibly due to recompositions), the closure will still only contain the initial object. And since you decided by using Unit
to never recompose pointerInput
, that closure will also never be refreshed with the current value. So whatever you do to the state in the view model, it will never reach the pointerInput
lambda.
Long story short: You need to either replace Unit
by state
or move the log statements outside of pointerInput
.