Android无法获取GPS坐标:代码实现异常求助
Hey there! Let's break down why your app isn't grabbing the location even though GPS is enabled and permissions are set up correctly. After looking through your code, I've spotted several key issues that are causing this stuck loading dialog:
1. Duplicate & Conflicting Location Listener Registrations
You're registering two separate LocationListeners with different providers:
- One outside the
FetchCordinatesAsyncTask usingGPS_PROVIDER - Another inside the AsyncTask using
NETWORK_PROVIDER
This creates two big problems:
- The outer listener is never removed, leading to potential memory leaks over time
- Your AsyncTask only waits for the network provider to update the
lativariable. If network-based location fails (even if GPS is working), the loop will run forever.
2. Infinite Loop in doInBackground (No Timeout)
The doInBackground method has a tight, unregulated loop:
while (this.lati == 0.0 && !isCancelled()) { }
This does nothing but wait for lati to change—but there's no timeout. If the location provider can't return a position (e.g., weak GPS/network signal), your app will stay stuck here indefinitely, showing the loading dialog forever.
3. Unoptimized Location Handling
In your VeggsterLocationListener, you're casting latitude/longitude to int (even though it's commented out), which is unnecessary and could lead to confusion. More importantly, once a location is received, you don't explicitly signal the AsyncTask to exit its loop—you just update the lati variable, which relies on the loop checking it constantly.
4. No Fallback Between Providers
Your code only uses NETWORK_PROVIDER in the AsyncTask, but if network location isn't available (even with GPS enabled), you won't get a position. You should prioritize GPS first, then fall back to network, or use a more robust solution that handles this automatically.
Fixed Code & Improvements
Let's rewrite the code to fix these issues, add a timeout, and streamline the location fetching logic:
// Remove the outer mlocManager and mlocListener code entirely—we'll handle everything in the AsyncTask public boolean startLocationFetch() { try { new FetchCoordinates().execute(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } private class FetchCoordinates extends AsyncTask<Void, Void, Boolean> { private AlertDialog dialog; private LocationManager locationManager; private LocationListener locationListener; private boolean locationReceived = false; private static final long TIMEOUT_MS = 30000; // 30-second timeout to avoid infinite loading @Override protected void onPreExecute() { // Set up loading dialog AlertDialog.Builder a = new AlertDialog.Builder(Admins.this); a.setMessage("در حال به دست آوردن موقعیت جغرافیایی..."); a.setPositiveButton("بیخیال", (dialogInterface, i) -> { dialogInterface.cancel(); cancel(true); }); dialog = a.show(); TextView messageText = dialog.findViewById(android.R.id.message); messageText.setGravity(Gravity.RIGHT); messageText.setTypeface(typeface); // Initialize location manager and single listener for both providers locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { if (!locationReceived && location != null) { locationReceived = true; // Capture and log coordinates double latitude = location.getLatitude(); double longitude = location.getLongitude(); Log.v("Location", "Lat: " + latitude + ", Long: " + longitude); // Use these coordinates for your app's logic here } } @Override public void onProviderDisabled(String provider) { Log.i("Location", provider + " disabled"); } @Override public void onProviderEnabled(String provider) { Log.i("Location", provider + " enabled"); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.i("Location", provider + " status updated: " + status); } }; // Request updates from both GPS and Network providers try { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); } catch (SecurityException e) { e.printStackTrace(); // Shouldn't happen with proper permissions } try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener); } catch (SecurityException e) { e.printStackTrace(); } } @Override protected Boolean doInBackground(Void... voids) { long startTime = System.currentTimeMillis(); // Wait for location or timeout while (!locationReceived && !isCancelled() && (System.currentTimeMillis() - startTime) < TIMEOUT_MS) { try { Thread.sleep(1000); // Avoid tight loop that eats CPU } catch (InterruptedException e) { e.printStackTrace(); cancel(true); } } // Clean up listener to prevent memory leaks if (locationManager != null && locationListener != null) { locationManager.removeUpdates(locationListener); } return locationReceived; } @Override protected void onPostExecute(Boolean locationSuccess) { dialog.dismiss(); if (locationSuccess) { Log.v("this", "Successfully retrieved location!"); // Add your post-location logic here } else { Log.v("this", "Failed to get location within timeout"); Toast.makeText(Admins.this, "ناتوان در دریافت موقعیت", Toast.LENGTH_LONG).show(); } } @Override protected void onCancelled() { super.onCancelled(); dialog.dismiss(); if (locationManager != null && locationListener != null) { locationManager.removeUpdates(locationListener); } Log.v("this", "Location fetch cancelled by user"); } } // Trigger location fetch when GPS is enabled LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { startLocationFetch(); }
Extra Tips for Better Location Handling
- Use Fused Location Provider: The old
LocationManageris less reliable. Google's Fused Location Provider (part of Google Play Services) automatically handles GPS/network fallback, improves accuracy, and simplifies code. - Replace AsyncTask: AsyncTask is deprecated in API 30+. Use Kotlin Coroutines,
ExecutorService, orWorkManagerfor background tasks instead. - Double-Check Runtime Permissions: Even if you think permissions are granted, ensure you're requesting
ACCESS_FINE_LOCATION(for GPS) orACCESS_COARSE_LOCATION(for network) at runtime (required for Android 6.0+).
内容的提问来源于stack exchange,提问作者Navid Abutorab

