Android应用从最小化恢复后Google Maps的OnLocationChanged未触发问题
嗨,这个问题我之前碰到过好几个开发者咨询,核心问题基本都和组件生命周期的回调绑定丢失有关。咱们一步步来排查和解决:
1. 最常见原因:位置更新回调在后台未注销,恢复时未重新注册
当应用最小化时,Fragment会触发onPause/onStop生命周期方法,如果你的LocationListener(或者FusedLocationProvider的LocationCallback)没有在此时注销,系统可能会回收这个回调的绑定;而当应用恢复时,又没有重新注册,自然就收不到位置更新了。
正确的做法是在onResume中注册位置更新,onPause中注销,既保证恢复时能重新绑定,也避免后台不必要的耗电:
private lateinit var fusedLocationClient: FusedLocationProviderClient private lateinit var locationCallback: LocationCallback private var googleMap: GoogleMap? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_map, container, false) // 初始化FusedLocationClient和回调 fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireContext()) locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult) { locationResult.lastLocation?.let { location -> Log.d("LocationUpdate", "Lat: ${location.latitude}, Lng: ${location.longitude}") // 更新地图标记位置 googleMap?.let { map -> val markerPosition = LatLng(location.latitude, location.longitude) map.moveCamera(CameraUpdateFactory.newLatLngZoom(markerPosition, 15f)) // 如果标记已存在就更新位置,否则创建 map.addMarker(MarkerOptions().position(markerPosition))?.let { marker -> marker.position = markerPosition } } } } } // 初始化地图 val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment mapFragment.getMapAsync { map -> googleMap = map map.isMyLocationEnabled = true // 绑定地图生命周期,避免状态丢失 lifecycle.addObserver(map) } return view } override fun onResume() { super.onResume() // 检查权限后重新请求位置更新 if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { val locationRequest = LocationRequest.create().apply { interval = 10000 // 10秒更新一次 fastestInterval = 5000 // 最快5秒更新 priority = LocationRequest.PRIORITY_HIGH_ACCURACY } fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()) } else { // 如果权限未授予,重新请求 requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001) } } override fun onPause() { super.onPause() // 暂停位置更新,释放资源 fusedLocationClient.removeLocationUpdates(locationCallback) }
2. 排查Fragment是否被系统重建
如果你的设备内存不足,应用最小化后Fragment可能会被系统销毁,恢复时会重新创建。这时候原来的LocationListener实例已经失效,需要在Fragment重建时重新初始化所有位置相关组件。
可以在onViewCreated或者onActivityCreated中做初始化,而不是只在onCreateView中做一次,确保重建时能重新绑定。
3. 确认地图组件的生命周期绑定
确保你的SupportMapFragment或者MapView和当前Fragment的生命周期正确关联。比如上面代码中给googleMap添加了lifecycle.addObserver(map),这能保证地图的状态和Fragment同步,避免恢复时地图组件异常。
最后总结
90%的概率是因为没有在onResume中重新注册位置回调,按照上面的代码调整后,应该就能解决最小化恢复后标记不移动的问题了。如果还是不行,可以检查Logcat中是否有位置权限或者系统限制的报错信息,比如有些厂商的后台限制会阻止位置更新。
内容的提问来源于stack exchange,提问作者RagAnt

