我想在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是蓝牙ONOFF,即分别是truefalse.

bluetooth状态改变为ONOFF时,我正在使用LaunchedEffect收听bluetoothEnableState.这个很好用.现在问题出现了,

当活动开始时,在onResumeLaunchedEffect上调用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 

所以我想防止调用双倍时间函数,有没有办法解决这个问题?谢谢

推荐答案

我不理解您的用例,也不能编译您的代码,但由于您只想在蓝牙为ON时使用startScan,而在蓝牙使用OFF时使用stopScan,我认为您不需要在onResume中处理相同的调用/逻辑

// I don't think you need it here,
else if (event == Lifecycle.Event.ON_RESUME) {
      viewModel.handleBluetoothScanState(rememberPairScreenState.bluetoothAdapter)
}

因为LaunchedEffect已经对蓝牙状态的改变做出了react ,开(true)/关(false)并且它已经在您的视图模型中调用了相同的函数.

Android相关问答推荐

编写Landscape BoxWithRequests具有错误的高度.(aspectRatio matchHeight约束第一次未按预期工作)

我到底应该如何分享我的应用程序中的图片?

Play Google上发布的一款应用的房间数据库迁移

在Android中使用Room从SQlite数据库中获取实体列表的正确方式是什么?

如何在Jetpack Compose android中使用导航

Android-交叉引用表中的ForeignKey用于什么?

没有打开历史记录的活动意向 Select 器完成调用活动

Play store 的 Play 完整性与 Firebase 应用判断 Play 完整性

布局可组合项如何具有可测量和约束参数?

为什么我收到这个错误我需要安装 android studio

如何在Android中使用嵌套的Recyclerview

我的自定义小吃店不适合我的全宽屏幕尺寸

围绕动态大小的内容包装 Jetpack Compose Row?

Android Studio 复制类 kotlin

为什么我的应用程序使用这些信息?

Jetpack Compose 中的滑动按钮菜单

Jetpack Compose:mutableStateOf 不随流量更新

Jetpack Compose:对角拆分卡片并将内容放入其中

如何在 Android Studio 中使用 Github Copilot?

如何在 Kotlin 中使用反向绑定适配器将小写文本转换为大写?