Reputation: 887
There is some unresolved situation that happens with my code, my target is to change the property of an item in the "devices" list (update a boolean), The change should cause recompose of the view, but that doesn't happen, In addition, I can see that the item indeed changes with the debugger, but it also causes to add an additional item(an old copy without the included change) to show up in my list.
Is there any idea how I was wrong with the new value assignment?
The ViewModel
private val _uiState = mutableStateOf(BTPairingState())
val uiState: State<BTPairingState> get() = _uiState
This is how i edit the item in the list
if (handlerDeviceResponse.status != null) {
viewModelScope.launch {
uiState.value.devices.find { it.macAddress == handlerDeviceResponse.device.macAddress }?.isConnected = handlerDeviceResponse.status
_uiState.value = uiState.value.copy()
}
}
BTPairingState:
data class BTPairingState (
val devices: MutableList<BtDeviceItemUiModel> = mutableListOf(),
val deviceType: DeviceType = DeviceType.RFID,
)
The Data class
data class BtDeviceItemUiModel(
val name: String,
val macAddress : String,
var isConnected: Boolean = false
)
The Screen:
@Destination
@Composable
fun BTPairScreen(
viewModel: BTPairViewModel = hiltViewModel(),
) {
val state = viewModel.uiState
BTPairDevices(state.value.devices) { viewModel.deviceItemClicked(it) }
Upvotes: 2
Views: 1764
Reputation: 618
You can set a policy to control how the result of mutableStateOf report and merge changes to the state object.
If you writes:
private val _uiState = mutableStateOf(BTPairingState(), neverEqualPolicy())
every write to _uiState.value will trigger recomposition, but you should of course consider pros and cons of such behavior. You can read more here:
https://developer.android.com/reference/kotlin/androidx/compose/runtime/SnapshotMutationPolicy
Upvotes: 0
Reputation: 661
In your viewmodel Change state to StateFlow
private val _uiState = MutableStateFlow(BTPairingState())
val uiState: StateFlow<BTPairingState> = _uiState.asStateFlow()
In your BTPairScreen Instead of
val state = viewModel.uiState
Use:
val state by viewModel.state.collectAsState()
Upvotes: 0
Reputation: 1007554
Replace var isConnected
by val isConnected
.
Then, replace val devices: MutableList<BtDeviceItemUiModel> = mutableListOf()
by val devices: List<BtDeviceItemUiModel> = emptyList()
.
IOW, stop using mutable values inside of your state.
Then, you can revise your code to update your MutableState
with a new value, using something like:
if (handlerDeviceResponse.status != null) {
val newDevices = uiState.value.devices.map { device ->
if (device.macAddress == handlerDeviceResponse.device.macAddress) {
device.copy(isConnected = handlerDeviceResponse.status)
} else {
it
}
}
_uiState.value = uiState.value.copy(devices = newDevices)
}
Upvotes: 4