安卓端Google设置开关定位后FusedLocation失效问题求助
Hey Walter, let's break down this frustrating issue you're facing—nothing's more annoying than location logic breaking just because a user toggles their system location settings. The good news is this is usually fixable by addressing how your app handles permission and service state changes, rather than needing a reinstall every time.
Common Causes & Fixes
1. Your App Isn't Rechecking Permissions After Location Toggles
When a user turns location services off and back on, Android's permission state can get out of sync with your app's cached understanding. FusedLocation will return null if it doesn't have valid permissions, even if location is enabled now.
Fix:
Add permission checks in onResume() (not just onCreate()) to ensure you have active location permissions whenever the app comes back to the foreground. If permissions are missing, re-request them:
override fun onResume() { super.onResume() val hasFineLocation = ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED val hasCoarseLocation = ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED if (!hasFineLocation && !hasCoarseLocation) { // Request permissions using ActivityResultContracts permissionLauncher.launch( arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ) ) } else { // Re-initialize location updates now that permissions are valid restartLocationUpdates() } } // Define the permission launcher in your activity private val permissionLauncher = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> val isGranted = permissions.values.all { it } if (isGranted) { restartLocationUpdates() } }
2. FusedLocationProviderClient Isn't Reinitialized After Service Toggles
Once location services are disabled, the FusedLocation client can enter an invalid state. If you only initialize it once in onCreate(), it won't automatically recover when location is re-enabled.
Fix:
Create a reusable method to set up location updates, and call it whenever location services are confirmed to be active (like after permission grants or service state changes):
private lateinit var fusedLocationClient: FusedLocationProviderClient private lateinit var locationCallback: LocationCallback private fun restartLocationUpdates() { fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) // Remove any old callbacks first to avoid duplicates fusedLocationClient.removeLocationUpdates(locationCallback) val locationRequest = LocationRequest.create().apply { priority = LocationRequest.PRIORITY_HIGH_ACCURACY interval = 10000 // 10 seconds fastestInterval = 5000 // 5 seconds } locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult?) { locationResult?.lastLocation?.let { currentLocation -> // Run your location comparison logic here compareWithTargetLocation(currentLocation) } ?: run { Toast.makeText(this@YourActivity, "location : null", Toast.LENGTH_SHORT).show() } } } // Request fresh location updates fusedLocationClient.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) }
3. You're Relying on Stale Cached Location
getLastLocation() often returns null after location services are toggled off (since the cached location is cleared). Don't rely on this method alone—actively request real-time updates instead.
Bonus Tip for API 30+:
Use getCurrentLocation() to fetch a fresh location immediately when services are re-enabled:
fusedLocationClient.getCurrentLocation( LocationRequest.PRIORITY_HIGH_ACCURACY, object : CancellationToken() { override fun isCancellationRequested() = false override fun onCanceledRequested(listener: OnTokenCanceledListener) = this } ).addOnSuccessListener { location -> location?.let { compareWithTargetLocation(it) } ?: run { Toast.makeText(this, "location : null", Toast.LENGTH_SHORT).show() } }
4. You're Not Listening for Location Service State Changes
Android broadcasts an intent when location services are toggled. Listen for this to trigger a reset of your location logic automatically:
private val locationStateReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == LocationManager.MODE_CHANGED_ACTION) { val locationMode = Settings.Secure.getInt( context?.contentResolver, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF ) if (locationMode != Settings.Secure.LOCATION_MODE_OFF) { // Location is back on—restart your location flow restartLocationUpdates() } } } } // Register the receiver in onCreate() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... your existing onCreate code registerReceiver( locationStateReceiver, IntentFilter(LocationManager.MODE_CHANGED_ACTION) ) } // Don't forget to unregister in onDestroy() override fun onDestroy() { super.onDestroy() unregisterReceiver(locationStateReceiver) fusedLocationClient.removeLocationUpdates(locationCallback) }
Why Reinstall Fixes It
Reinstalling your app resets permission status and forces your onCreate() logic to run fresh, which reinitializes the FusedLocation client and requests permissions again. The fixes above replicate this behavior without needing a reinstall.
内容的提问来源于stack exchange,提问作者Walter

