Android Studio中FusedLocationProviderClient定位偶尔失效的解决方案咨询
Great question! The issue you're hitting with getLastLocation() is really common—let me break down why it happens and walk you through a rock-solid solution to get a location every time.
Why getLastLocation() Fails Sometimes
The getLastLocation() method only returns the last cached location the system has stored. If your device hasn't had a recent location fix (like on first app launch, after turning on location services, or if it's been hours since the last update), this method will return null—which triggers that error toast you're seeing. Also, quick typo in your code: you used SearchActivity.this in the error toast, but it should be LocationActivity.this to avoid a context mismatch.
Step-by-Step Reliable Implementation
Let's build a solution that actively requests a fresh location instead of relying on cached data, plus handles permissions and location service checks.
1. Add Permissions to AndroidManifest.xml
First, make sure you have the necessary permissions declared:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Add this only if you need background location access (Android 12+) --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="33" />
2. Dynamic Permission Request
Since location permissions are "dangerous" permissions, you need to ask the user for approval at runtime:
private static final int REQUEST_LOCATION_PERMISSION = 100; private boolean checkLocationPermissions() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { return true; } // Request permission if not granted ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION); return false; } // Handle permission request result @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_LOCATION_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission granted, start location request requestFreshLocation(); } else { Toast.makeText(this, "Location permission is required to get your location", Toast.LENGTH_LONG).show(); } } }
3. Check if Location Services are Enabled
Before requesting location, verify that the user has turned on location services. If not, send them to settings to enable it:
private boolean isLocationEnabled() { LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); } private void promptEnableLocation() { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); }
4. Request Fresh Location Updates
Instead of getLastLocation(), use requestLocationUpdates() to get a live location fix. We'll also use a LocationCallback to handle the result, and clean up updates when we're done to save battery:
private FusedLocationProviderClient fusedLocationProviderClient; private LocationCallback locationCallback; private LocationRequest locationRequest; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_location); fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); setupLocationCallback(); setupLocationRequest(); // Check permissions and location services first if (checkLocationPermissions()) { if (isLocationEnabled()) { requestFreshLocation(); } else { promptEnableLocation(); Toast.makeText(this, "Please enable location services", Toast.LENGTH_LONG).show(); } } } private void setupLocationRequest() { locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // Use PRIORITY_BALANCED_POWER_ACCURACY for lower battery use locationRequest.setInterval(10000); // 10 seconds interval (adjust as needed) locationRequest.setFastestInterval(5000); // Fastest update interval } private void setupLocationCallback() { locationCallback = new LocationCallback() { @Override public void onLocationResult(@NonNull LocationResult locationResult) { super.onLocationResult(locationResult); if (locationResult != null && locationResult.getLocations().size() > 0) { int latestLocationIndex = locationResult.getLocations().size() - 1; Location location = locationResult.getLocations().get(latestLocationIndex); // Use the location data double latitude = location.getLatitude(); double longitude = location.getLongitude(); String latitudeStr = String.valueOf(latitude); String longitudeStr = String.valueOf(longitude); Toast.makeText(LocationActivity.this, latitudeStr + " " + longitudeStr, Toast.LENGTH_LONG).show(); // Stop location updates once we have the location to save battery fusedLocationProviderClient.removeLocationUpdates(locationCallback); } else { Toast.makeText(LocationActivity.this, "Your Location Could Not Be Found !!!", Toast.LENGTH_LONG).show(); } } }; } private void requestFreshLocation() { try { fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); } catch (SecurityException e) { // This shouldn't happen if we checked permissions first, but handle it just in case e.printStackTrace(); Toast.makeText(this, "Location permission not granted", Toast.LENGTH_LONG).show(); } } // Clean up location updates when activity is paused/destroyed to avoid memory leaks @Override protected void onPause() { super.onPause(); if (fusedLocationProviderClient != null && locationCallback != null) { fusedLocationProviderClient.removeLocationUpdates(locationCallback); } }
Key Notes
- Priority Setting: Use
PRIORITY_HIGH_ACCURACYfor precise GPS location, orPRIORITY_BALANCED_POWER_ACCURACYif you don't need pinpoint accuracy and want to save battery. - Stop Updates: Always call
removeLocationUpdates()once you have the location (or when the activity is paused) to prevent unnecessary battery drain. - Edge Cases: The code handles permission denials, disabled location services, and security exceptions to make your app robust.
This implementation will reliably get a fresh location every time, instead of relying on potentially stale cached data.
内容的提问来源于stack exchange,提问作者Rick

