当我使用双精度值时,它会丢失该值并使用 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()
}
}
但请注意,在配置更改期间它仍会被重置,例如屏幕旋转。
要在配置更改期间保存它,您有两个选择:
- 使用
rememberSaveable
。在这种情况下,它可能不是最佳解决方案,因为您必须以某种方式序列化您的对象。
- 将您的
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)
}
我的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()
}
}
但请注意,在配置更改期间它仍会被重置,例如屏幕旋转。
要在配置更改期间保存它,您有两个选择:
- 使用
rememberSaveable
。在这种情况下,它可能不是最佳解决方案,因为您必须以某种方式序列化您的对象。 - 将您的
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)
}