我想在Jetpack编写中根据生命周期更改变量值或调用函数.我试着按这answer来算.也是从doc开始读的.我做了这件事,没有任何问题.
我有@Composable
个功能
@Composable
fun BluetoothConnectionContentStateful(
context: Context = LocalContext.current,
viewModel: PairViewModel = getViewModel()
) {
var selectedIndexOfAvailableItem by remember { mutableStateOf(DEVICE_NOT_SELECTED_INDEX) }
val rememberPairScreenState = rememberConnectionScreenState(context, viewModel)
val bluetoothEnableState by remember { derivedStateOf { viewModel.isBluetoothEnabled } }
LaunchedEffect(key1 = bluetoothEnableState) {
viewModel.handleBluetoothScanState(rememberPairScreenState.bluetoothAdapter)
}
LaunchedEffect(key1 = selectedIndexOfAvailableItem) {
viewModel.handleTimeWarning(selectedIndexOfAvailableItem)
}
ComposableLifecycle { source, event ->
if (event == Lifecycle.Event.ON_PAUSE) {
viewmodel.stopScan()
} else if (event == Lifecycle.Event.ON_RESUME) {
viewModel.handleBluetoothScanState(rememberPairScreenState.bluetoothAdapter)
}
}
}
ComposableLifecycle个
@Composable
fun ComposableLifecycle(
lifeCycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
onEvent: (LifecycleOwner, Lifecycle.Event) -> Unit
) {
DisposableEffect(lifeCycleOwner) {
val observer = LifecycleEventObserver { source, event ->
onEvent(source, event)
}
lifeCycleOwner.lifecycle.addObserver(observer)
onDispose {
lifeCycleOwner.lifecycle.removeObserver(observer)
}
}
}
PairViewModel个
class PairViewModel : BaseViewModel() {
companion object {
private const val WARNING_PERIOD_IN_MILLES: Long = 60000 // For 1 minute scan
const val DEVICE_NOT_SELECTED_INDEX = -1
}
var isBluetoothEnabled by mutableStateOf(false)
private set
private var job = Job()
get() {
if (field.isCancelled) field = Job()
return field
}
fun startScan(adapter: BluetoothAdapter) = viewModelScope.launch {
// start scan
}
fun stopScan(adapter: BluetoothAdapter) {
// stop scan
}
fun handleBluetoothScanState(bluetoothAdapter: BluetoothAdapter) {
if (isBluetoothEnabled) {
startScan(bluetoothAdapter)
} else {
cancelTimeWarning()
stopScan(bluetoothAdapter)
}
}
fun handleTimeWarning(selectedIndexOfAvailableItem: Int) {
if (selectedIndexOfAvailableItem == DEVICE_NOT_SELECTED_INDEX) {
startTimeWarning()
} else {
cancelTimeWarning()
}
}
fun startTimeWarning() {
viewModelScope.launch(job) {
delay(WARNING_PERIOD_IN_MILLES)
// make event here
}
}
internal fun cancelTimeWarning() {
if (job.isActive) {
job.cancel()
}
// make event here
}
}
Note bluetoothEnableState
是蓝牙ON和OFF,即分别是true和false.
当bluetooth状态改变为ON或OFF时,我正在使用LaunchedEffect
收听bluetoothEnableState
.这个很好用.现在问题出现了,
当活动开始时,在onResume
和LaunchedEffect
上调用viewModel.handleBluetoothScanState(rememberPairScreenState.bluetoothAdapter)
两次.
2.当用户禁用蓝牙时,它的状态更改为false
,他将转到onPause
.在返回onResume
之后,handleBluetoothScanState
将呼叫并且还将蓝牙状态改变为true,然后再次呼叫LaunchedEffect
.
我会解释更多关于第二种情况的细节
On Resume Close App Open App
Bluetooth disable -> On Pause -> OnResume -> Bluetooth enable
| | |
\ / \ / \ /
Launcheffect function Launcheffect
所以我想防止调用双倍时间函数,有没有办法解决这个问题?谢谢