当我使用双精度值时,它会丢失该值并使用 collectAsState 打印数字 0.0

When I use the double value it loses the value and prints number 0.0 using collectAsState

我的class取位置:

class LocationUtil(context: Context) {

    private val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    private var locationListener: LocationListener? = null

    var locationStateFlow = MutableStateFlow(Location(LocationManager.GPS_PROVIDER))
    val gpsProviderState = mutableStateOf(false)
    val isStart: MutableState<Boolean> = mutableStateOf(false)

    private val locHandlerThread = HandlerThread("LocationUtil Thread")

    init {
        locHandlerThread.start()
    }

    @SuppressLint("MissingPermission")
    fun start(minTimeMs: Long = min_time, minDistanceM: Float = min_distance) {

        locationListener().let {
            locationListener = it

            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTimeMs, minDistanceM, it, locHandlerThread.looper)

        }
        gpsProviderState.value = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        isStart.value = true
    }

    @SuppressLint("MissingPermission")
    fun stop() {
        locationListener?.let {
            locationManager.removeUpdates(it)
        }
        isStart.value = false
    }


    private fun locationListener() = object : LocationListener {
        override fun onLocationChanged(location: Location) {

            locationStateFlow.value = location
            Log.i("GPS",locationStateFlow.value.longitude.toString()+">>"+locationStateFlow.value.latitude.toString())
        }

        @Deprecated("Deprecated in Java")
        override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
        }

        override fun onProviderEnabled(provider: String) {
            gpsProviderState.value = true
        }

        override fun onProviderDisabled(provider: String) {
            gpsProviderState.value = false
        }
    }


    companion object {
        const val min_time: Long = 0L
        const val min_distance: Float = 0f
    }

}

我的可组合方法采用变量 var locationStateFlow = MutableStateFlow(Location(LocationManager.GPS_PROVIDER)) 的值:

@Composable
private fun FeatureThatRequiresCameraPermission(multiplePermissionsState: MultiplePermissionsState) {
    if (multiplePermissionsState.allPermissionsGranted) {
        // If all permissions are granted, then show screen with the feature enabled
        val context = LocalContext.current
        val locationUtil = LocationUtil(context)
        locationUtil.start()
        val gpsEnable by locationUtil.gpsProviderState
        val coordenadas by locationUtil.locationStateFlow.collectAsState(
                Location(
                        LocationManager.GPS_PROVIDER)
        )

        Text(text = coordenadas.latitude.toString())

    } else {
        Column {
            Spacer(modifier = Modifier.height(8.dp))
            Button(onClick = { multiplePermissionsState.launchMultiplePermissionRequest() }) {
                Text("Request permissions")
            }
        }
    }
}

我的Text(text = coordinates.latitude.toString())returns0.0 但是我的坐标方法 returns 正确:

 override fun onLocationChanged(location: Location) {

            locationStateFlow.value = location
            Log.i("GPS",locationStateFlow.value.longitude.toString()+">>"+locationStateFlow.value.latitude.toString())
        }

有谁知道为什么我无法正确获取值?

每次您的流发出新值时,collectAsState 都会触发重组。这意味着,整个 FeatureThatRequiresCameraPermission 被再次调用。

在每次重组时,您都会创建一个新的 LocationUtil,它的初始坐标为零。此外,您每次都在调用 start()

val locationUtil = LocationUtil(context)
locationUtil.start()

在重组之间保存一些对象的最简单的解决方案是使用 remember,例如,像这样:

val locationUtil = remember {
    LocationUtil(context)
        .apply {
            start()
        }
}

但请注意,在配置更改期间它仍会被重置,例如屏幕旋转。

要在配置更改期间保存它,您有两个选择:

  1. 使用rememberSaveable。在这种情况下,它可能不是最佳解决方案,因为您必须以某种方式序列化您的对象。
  2. 将您的 LocationUtil 转换为 view model - 它的生命周期与您的 activity/fragment 或导航路线(如果您使用的是 Compose Navigation)紧密相关。您可以将 context 传递给 start,它看起来像这样:
class LocationViewModel: ViewModel() {

    private lateinit var locationManager: LocationManager
    private var locationListener: LocationListener? = null

    var locationStateFlow = MutableStateFlow(Location(LocationManager.GPS_PROVIDER))
    var gpsProviderState by mutableStateOf(false)
        private set
    var isStart by mutableStateOf(false)
        private set

    private val locHandlerThread = HandlerThread("LocationUtil Thread")

    init {
        locHandlerThread.start()
    }

    fun start(context: Context, minTimeMs: Long = min_time, minDistanceM: Float = min_distance) {
        // LaunchedEffect is gonna be re-launched during configuration change
        // we don't need to re-start if it's running
        if (isStart) return
        if (!this::locationManager.isInitialized) {
            locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        }
        locationListener().let {
            locationListener = it

            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTimeMs, minDistanceM, it, locHandlerThread.looper)
        }
        gpsProviderState = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        isStart = true
    }

    fun stop() {
        locationListener?.let {
            locationManager.removeUpdates(it)
        }
        isStart = false
    }


    private fun locationListener() = object : LocationListener {
        override fun onLocationChanged(location: Location) {

            locationStateFlow.value = location
            Log.i("GPS",locationStateFlow.value.longitude.toString()+">>"+locationStateFlow.value.latitude.toString())
        }

        @Deprecated("Deprecated in Java")
        override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
        }

        override fun onProviderEnabled(provider: String) {
            gpsProviderState = true
        }

        override fun onProviderDisabled(provider: String) {
            gpsProviderState = false
        }
    }


    companion object {
        const val min_time: Long = 0L
        const val min_distance: Float = 0f
    }
}

用法:

val locationViewModel = viewModel<LocationViewModel>()
val context = LocalContext.current
LaunchedEffect(Unit) {
    locationViewModel.start(context)
}