I want to avoid multiple function call when LaunchEffect
key triggers.
LaunchedEffect(key1 = isEnableState, key2 = viewModel.uiState) {
viewModel.scanState(bluetoothAdapter)
}
when first composition isEnableState
and viewModel.uiState
both will trigger twice and call viewModel.scanState(bluetoothAdapter)
.
isEnableState
is a Boolean
type and viewModel.uiState
is sealed class of UI types.
var uiState by mutableStateOf<UIState>(UIState.Initial)
private set
var isEnableState by mutableStateOf(false)
private set
So how can we handle idiomatic way to avoid duplicate calls?
Thanks
UPDATE
ContentStateful
@Composable
fun ContentStateful(
context: Context = LocalContext.current,
viewModel: ContentViewModel = koinViewModel(),
) {
LaunchedEffect(key1 = viewModel.isEnableState, key2 = viewModel.uiState) {
viewModel.scanState(bluetoothAdapter)
}
LaunchedEffect(viewModel.previous) {
viewModel.changeDeviceSate()
}
ContentStateLess{
viewModel.isEnableState = false
}
}
ContentStateLess
@Composable
fun ContentStateLess(changeAction: () -> Unit) {
Button(onClick = { changeAction() }) {
Text(text = "Click On me")
}
}
ContentViewModel
class ContentViewModel : BaseViewModel() {
var uiState by mutableStateOf<UIState>(UIState.Initial)
var isEnableState by mutableStateOf(false)
fun scanState(bluetoothAdapter: BluetoothAdapter) {
if (isEnableState && isInitialOrScanningUiState()) {
// start scanning
} else {
// stop scanning
}
}
private fun isInitialOrScanningUiState(): Boolean {
return (uiState == UIState.Initial || uiState == UIState.ScanningDevice)
}
fun changeDeviceSate() {
if (previous == BOND_NONE && newState == BONDING) {
uiState = UIState.LoadingState
} else if (previous == BONDING && newState == BONDED) {
uiState = UIState.ConnectedState(it)
} else {
uiState = UIState.ConnectionFailedState
}
}
}
scanState
function is start and stop scanning of devices.
CodePudding user response:
I guess the answer below would work or might require some modification to work but logic for preventing double clicks can be used only if you wish to prevent actions happen initially within time frame of small interval. To prevent double clicks you you set current time and check again if the time is above threshold to invoke click callback. In your situation also adding states with delay might solve the issue.
IDLE, BUSY, READY
var launchState by remember {mutableStateOf(IDLE)}
LaunchedEffect(key1 = isEnableState, key2 = viewModel.uiState) {
if(launchState != BUSY){
viewModel.scanState(bluetoothAdapter)
if(launchState == IDLE){ launchState = BUSY)
}
}
LaunchedEffect(launchState) {
if(launchState == BUSY){
delay(50)
launchState = READY
}
}