安卓应用无法获取位置求助:需等待一天才能获取当前/已知位置(附代码)
Fixing Your Location Fetching Issue for the Used Goods App
Hey Edson, let's break down why your app is taking a full day to get location data and fix it right away—your code has a few critical bugs that are blocking location updates, plus some easy tweaks to make it more reliable.
First, Let's Spot the Critical Bugs in Your Current Code
- Reversed Permission Check in
onLocationChanged: This is the biggest problem! You wrote:
This means if the user has granted permissions, you immediately exit the method without processing the location data. That's why you never get any location updates at all!if (PermissionsUtils.hasPermissions(this, locationPermissions)) { return; } - No Fallback for Empty
getLastKnownLocation: If there's no saved location, you request updates but don't handle cases where the device can't get a fix quickly. - Overly Aggressive Update Parameters:
requestLocationUpdates(provider, 1000, 0, this)asks for updates every 1 second and every 0 meters—this is too frequent, drains battery, and might cause the system to throttle your requests.
Fixed Version of Your Code
Let's rewrite the location logic with these fixes, plus add proper permission handling:
// MARK: - GET CURRENT LOCATION ------------------------------------------------------ protected void getCurrentLocation() { // First, check if permissions are granted—if not, request them if (!PermissionsUtils.hasPermissions(this, locationPermissions)) { ActivityCompat.requestPermissions(this, locationPermissions, 1001); return; } Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); // Use coarse for faster fixes, switch to fine if needed criteria.setPowerRequirement(Criteria.POWER_LOW); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); assert locationManager != null; String provider = locationManager.getBestProvider(criteria, true); // Try last known location first currentLocation = locationManager.getLastKnownLocation(provider); if (currentLocation != null) { getCityCountryNames(); queryAds(); // Don't forget to trigger your ad query here } else { // Request a single location update (not continuous) with a timeout locationManager.requestSingleUpdate(provider, this, Looper.getMainLooper()); // Add a timeout in case location takes too long new Handler(Looper.getMainLooper()).postDelayed(() -> { if (currentLocation == null) { // Fallback to default location if no fix after 10 seconds Configs.simpleAlert(getString(R.string.get_location_failure), AdsListActivity.this); currentLocation = new Location("provider"); currentLocation.setLatitude(Configs.DEFAULT_LOCATION.latitude); currentLocation.setLongitude(Configs.DEFAULT_LOCATION.longitude); cityCountryTV.setText(getString(R.string.not_available_text_placeholder)); queryAds(); } }, 10000); // 10-second timeout } } @Override public void onLocationChanged(Location location) { // Now, only return if permissions are NOT granted if (!PermissionsUtils.hasPermissions(this, locationPermissions)) { return; } // Stop listening for updates since we only need one fix if (locationManager != null) { locationManager.removeUpdates(this); } currentLocation = location; if (currentLocation != null) { getCityCountryNames(); queryAds(); // Trigger your ad query once location is found } else { // Fallback to default Configs.simpleAlert(getString(R.string.get_location_failure), AdsListActivity.this); currentLocation = new Location("provider"); currentLocation.setLatitude(Configs.DEFAULT_LOCATION.latitude); currentLocation.setLongitude(Configs.DEFAULT_LOCATION.longitude); cityCountryTV.setText(getString(R.string.not_available_text_placeholder)); queryAds(); } } // Handle permission request result @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1001) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permissions granted—try getting location again getCurrentLocation(); } else { // User denied permissions—use default location Configs.simpleAlert("Location permissions are required to show local ads", AdsListActivity.this); currentLocation = new Location("provider"); currentLocation.setLatitude(Configs.DEFAULT_LOCATION.latitude); currentLocation.setLongitude(Configs.DEFAULT_LOCATION.longitude); cityCountryTV.setText(getString(R.string.not_available_text_placeholder)); queryAds(); } } }
Key Improvements Made
- Fixed the Permission Check: Now
onLocationChangedonly exits if permissions are missing, so valid location data gets processed. - Added Permission Request Flow: If the user hasn't granted permissions, the app asks for them and retries location fetching once granted.
- Single Location Update: Used
requestSingleUpdateinstead of continuous updates—we only need one location fix, not ongoing tracking. - Timeout Fallback: If no location is found after 10 seconds, the app switches to your default location immediately instead of waiting indefinitely.
- Triggered
queryAds(): Ensured your ad query runs as soon as a valid location (or default) is set.
Bonus: Use Fused Location Provider (More Reliable for Modern Android)
The old LocationManager works but is less reliable on Android 10+. For better results, use Google's Fused Location Provider. Here's a quick snippet to get you started:
First, add this to your app-level build.gradle dependencies:
implementation 'com.google.android.gms:play-services-location:21.0.1'
Then update your location logic:
private FusedLocationProviderClient fusedLocationClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... your existing onCreate code fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); } protected void getCurrentLocation() { if (!PermissionsUtils.hasPermissions(this, locationPermissions)) { ActivityCompat.requestPermissions(this, locationPermissions, 1001); return; } // Get last known location first fusedLocationClient.getLastKnownLocation() .addOnSuccessListener(this, location -> { if (location != null) { currentLocation = location; getCityCountryNames(); queryAds(); } else { // Request a single high-priority location update LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); locationRequest.setNumUpdates(1); locationRequest.setInterval(0); locationRequest.setFastestInterval(0); fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); // Timeout fallback new Handler(Looper.getMainLooper()).postDelayed(() -> { if (currentLocation == null) { Configs.simpleAlert(getString(R.string.get_location_failure), AdsListActivity.this); // Set default location currentLocation = new Location("provider"); currentLocation.setLatitude(Configs.DEFAULT_LOCATION.latitude); currentLocation.setLongitude(Configs.DEFAULT_LOCATION.longitude); cityCountryTV.setText(getString(R.string.not_available_text_placeholder)); queryAds(); } }, 10000); } }); } private final LocationCallback locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); if (locationResult == null) { return; } for (Location location : locationResult.getLocations()) { if (location != null) { currentLocation = location; getCityCountryNames(); queryAds(); fusedLocationClient.removeLocationUpdates(this); } } } };
Final Notes
- Add Permissions to
AndroidManifest.xml: Make sure you have these lines:<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-feature android:name="android.hardware.location.gps" android:required="false" /> - Test with Location Enabled: Ensure the device's location services are turned on (GPS or Wi-Fi-based location).
内容的提问来源于stack exchange,提问作者Edson Francis
相关产品推荐
相关产品推荐

