Я хочу избежать вызова нескольких функций при срабатывании клавиши LaunchEffect
.
LaunchedEffect(key1 = isEnableState, key2 = viewModel.uiState) {
viewModel.scanState(bluetoothAdapter)
}
при первой композиции isEnableState
и viewModel.uiState
сработают дважды и вызовут viewModel.scanState(bluetoothAdapter)
.
isEnableState
— это тип Boolean
, а viewModel.uiState
— закрытый класс типов пользовательского интерфейса.
var uiState by mutableStateOf<UIState>(UIState.Initial)
private set
var isEnableState by mutableStateOf(false)
private set
Итак, как мы можем справиться с идиоматическим способом, чтобы избежать дублирования вызовов?
Спасибо
ОБНОВЛЯТЬ
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
}
}
Контентстателесс
@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
функция запуска и остановки сканирования устройств.
что нужно проверить внутри, если блок?
Вы используете 2 ключа, и они работают по назначению. Чего вы хотите избежать? Существуют ли некоторые состояния или комбинации, в которых не следует вызывать viewModel.scanState?
@Gabriele Mariotti isEnableState
меняется в каком-то состоянии, и я хочу вызвать scanState
. uiState
постоянно меняется, а также хочет активировать функцию. Моя основная проблема заключается в том, что когда происходит 1-я композиция, я не хочу дважды вызывать функцию scanState
. Я использовал оба ключа, потому что всякий раз, когда значение переменной изменяется, я хочу вызвать scanState
, но только один раз. Если вы не понимаете, спросите меня, я добавлю больше кода в свой пример.
Кажется, что оба ключа зависят друг от друга. Они меняются отдельно?
@Steyrix да, они меняются отдельно..
Что делает scanState
?
Это просто функция запуска и сканирования в фоновом режиме. я добавил свой код
Можете ли вы опубликовать полный код составной функции, в которой вы вызываете эффект запуска?
Полный код будет невозможен, вместо этого я добавлю соответствующий код.
@Steyrix Я добавил весь код, который использует isEnableState
и uiState
..
Не знаю, связано ли это, но кажется невозможным, чтобы это условие когда-либо было правдой. previous == BOND_NONE && previous == BONDING
То же самое с условием else-if.
@ Tenfour04 хороший улов, я забыл изменить переменную. Теперь это исправлено, пожалуйста, посмотрите.
Я предполагаю, что приведенный ниже ответ будет работать или может потребовать некоторой модификации для работы, но логика для предотвращения двойных щелчков может использоваться только в том случае, если вы хотите, чтобы действия не происходили изначально в течение небольшого интервала времени. Чтобы предотвратить двойные щелчки, вы устанавливаете текущее время и снова проверяете, превышает ли время пороговое значение для вызова обратного вызова щелчка. В вашей ситуации также может решить проблему добавление состояний с задержкой.
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
}
}
Можно ли вызвать запущенный эффект с scanState
второй раз? Он должен перейти из READY в BUSY.
launchState переходит в состояние IDLE, BUSY только при первой композиции и переходит в состояние READY через 50 мс или с определенной задержкой. Состояние ON READY после запуска работает как в вопросе. Он действует только как временный блокировщик в течение определенного времени.
@Thracian идеально работает, как и ожидалось. Спасибо
Добавьте условие if внутри блока.