使用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 } } }
错误原因
- Listener实例未持久化:
locationListener没有用remember修饰,每次Composable重组(比如点击按钮改变tracking状态时)都会创建新的Listener实例。停止追踪时,你移除的是当前新创建的Listener,而不是之前启动时注册的那个旧Listener,导致旧Listener仍绑定在LocationManager上,GPS继续运行。 - 缺少兜底清理:
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
相关产品推荐
相关产品推荐

