You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 FetchCordinates AsyncTask using GPS_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 lati variable. 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 LocationManager is 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, or WorkManager for background tasks instead.
  • Double-Check Runtime Permissions: Even if you think permissions are granted, ensure you're requesting ACCESS_FINE_LOCATION (for GPS) or ACCESS_COARSE_LOCATION (for network) at runtime (required for Android 6.0+).

内容的提问来源于stack exchange,提问作者Navid Abutorab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:31:45