You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用LocationManagerAPI无法停止GPS追踪问题排查

GPS追踪停止后仍持续运行的问题排查与修复

问题描述

我编写了如下用于追踪用户位置的Composable函数,尝试通过布尔变量tracking控制追踪启停,true时启动GPS追踪,false时停止,但点击停止后GPS仍持续追踪:

@SuppressLint("MissingPermission")
@Composable
fun GpsTracking() {
    val ctx = LocalContext.current
    val locationManager: LocationManager = ctx.getSystemService(Context.LOCATION_SERVICE) as LocationManager

    var latitude by remember { mutableStateOf(0.0) }
    var longitude by remember { mutableStateOf(0.0) }

    var tracking by remember { mutableStateOf(false) }

    var btnTextEnabled = if (tracking) "Ein" else "Aus"

    var locationListener: LocationListener? = null

    locationListener = object : LocationListener {
        override fun onLocationChanged(location: Location) {
            latitude = location.latitude
            longitude = location.longitude
            gpsList.add(System.currentTimeMillis().toString()+" "+latitude+" "+longitude+"\n")
        }
    }

    Button(onClick = { tracking = !tracking }) {
        Text(text = "GPS-Tracking: $btnTextEnabled")
    }

    DisposableEffect(tracking) {
        if (tracking) {
            Log.d("GPS-Tracking", "Tracking wird gestartet")
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 0f, locationListener as LocationListener
            )
            Log.d("GPS-Tracking", "Longitiude: $longitude\nLatitude: $latitude")
        } else {
            Log.d("GPS-Tracking", "Tracking wird gestoppt")
            locationManager.removeUpdates(locationListener as LocationListener)
            locationListener = null
        }

        onDispose {
            // Cleanup, if necessary
        }
    }
}

错误原因

  1. Listener实例未持久化:locationListener没有用remember修饰,每次Composable重组(比如点击按钮改变tracking状态时)都会创建新的Listener实例。停止追踪时,你移除的是当前新创建的Listener,而不是之前启动时注册的那个旧Listener,导致旧Listener仍绑定在LocationManager上,GPS继续运行。
  2. 缺少兜底清理:DisposableEffect的onDispose块没有做清理操作,当Composable被销毁时,Listener可能仍未被移除,造成内存泄漏和持续追踪。

修复后的代码

@SuppressLint("MissingPermission")
@Composable
fun GpsTracking() {
    val ctx = LocalContext.current
    val locationManager: LocationManager = ctx.getSystemService(Context.LOCATION_SERVICE) as LocationManager

    var latitude by remember { mutableStateOf(0.0) }
    var longitude by remember { mutableStateOf(0.0) }

    var tracking by remember { mutableStateOf(false) }
    val btnTextEnabled = if (tracking) "Ein" else "Aus"

    // 用remember保存Listener实例,确保重组时不会丢失引用
    val locationListener = remember {
        object : LocationListener {
            override fun onLocationChanged(location: Location) {
                latitude = location.latitude
                longitude = location.longitude
                gpsList.add("${System.currentTimeMillis()} $latitude $longitude\n")
            }

            // 实现LocationListener的其他必要方法(API 30+需要)
            override fun onProviderEnabled(provider: String) {}
            override fun onProviderDisabled(provider: String) {}
            @Deprecated("Deprecated in Java")
            override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
        }
    }

    Button(onClick = { tracking = !tracking }) {
        Text(text = "GPS-Tracking: $btnTextEnabled")
    }

    DisposableEffect(tracking) {
        if (tracking) {
            Log.d("GPS-Tracking", "Tracking wird gestartet")
            locationManager.requestLocationUpdates(
                LocationManager.GPS_PROVIDER,
                1000L,
                0f,
                locationListener
            )
        } else {
            Log.d("GPS-Tracking", "Tracking wird gestoppt")
            locationManager.removeUpdates(locationListener)
        }

        // 兜底清理:当Composable销毁时,确保移除Listener
        onDispose {
            locationManager.removeUpdates(locationListener)
            Log.d("GPS-Tracking", "Tracking wurde durch Dispose gestoppt")
        }
    }
}

额外提示

  • 权限检查:务必在运行时申请位置权限(ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION),Android 12及以上版本如需后台追踪还需申请ACCESS_BACKGROUND_LOCATION,不要依赖@SuppressLint("MissingPermission")跳过检查。
  • 状态管理:gpsList如果是全局变量,建议改用rememberSaveable或ViewModel管理,避免内存泄漏和状态丢失。
  • API兼容:LocationListener在API 30+中部分方法已过时,需实现所有必要的方法,避免编译错误。

内容的提问来源于stack exchange,提问作者Phisma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:10:11