Android GPS incorrect location data on query

后端 未结 2 1913
遥遥无期
遥遥无期 2020-11-30 11:59

I am not using mock locations for this... In fact the code was working fine just last week.

I have an app that gathers GPS data and spits out a google maps link usin

相关标签:
2条回答
  • 2020-11-30 12:13

    You should check out http://developer.android.com/guide/topics/location/strategies.html. There are some nice strategies to obtain accurate locations on this page. Here is some example code I've take from the site:

    private static final int TWO_MINUTES = 1000 * 60 * 2;
    
    /** Determines whether one Location reading is better than the current Location fix
      * @param location  The new Location that you want to evaluate
      * @param currentBestLocation  The current Location fix, to which you want to compare the new one
      */
    protected boolean isBetterLocation(Location location, Location currentBestLocation) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }
    
        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
        boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
        boolean isNewer = timeDelta > 0;
    
        // If it's been more than two minutes since the current location, use the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return true;
        // If the new location is more than two minutes older, it must be worse
        } else if (isSignificantlyOlder) {
            return false;
        }
    
        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;
    
        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());
    
        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }
    
    /** Checks whether two providers are the same */
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
          return provider2 == null;
        }
        return provider1.equals(provider2);
    }
    
    0 讨论(0)
  • 2020-11-30 12:26

    From what is specified[difference of 4-5 blocks], you may be obtaining the location from networkProvider only.

    With this gpsTracker code mentioned in the question,
    there are a few modifications required, instead of using the code as it is:

    1. There are 2 if loops which verify the source of location is enabled or not and No 'else':

     if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    Log.d("Network", "Network");
                    if (locationManager != null) {
                        location = locationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
                        }
                    }
                }
                // if GPS Enabled get lat/long using GPS Services
                if (isGPSEnabled) {
                    if (location == null) {
                        locationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        Log.d("GPS Enabled", "GPS Enabled");
                        if (locationManager != null) {
                            location = locationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                }  
    

    This means the application is going to do twice the work when you can obtain the location from both sources. Further, the source of location obtained always remains ambiguous.

    This is good when you just need approximate location which should not be null majorly.

    If you want to use only this class to obtain location, try structuring the if-else according to requirement and ensuring that its not going to repeat if the location is obtained.
    Eg. if GPS is on a higher preference, applies in your case, shift that if above and put the network condition with an else like:

    if (isGPSEnabled) {
                    if (location == null) {
                        locationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        Log.d("GPS Enabled", "GPS Enabled");
                        if (locationManager != null) {
                            location = locationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                } else if (isNetworkEnabled) {
                locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER,
                        MIN_TIME_BW_UPDATES,
                        MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                Log.d("Network", "Network");
                if (locationManager != null) {
                    location = locationManager
                            .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                    if (location != null) {
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                    }
                }
            }
    

    For your requirement, i suggest removing the network provider part and obtaining the location only from GPS, esp if line of sight is not a problem.

    When your code was working fine, it must be fetching the location from GPS and setting it in the object. But because of the two "if" and no "else", you'l never know whether location obtained is from Network or GPS - you can check location.getProvider() inside the condition of canGetLocation()

    2. Also, you can log the message or prompt some action for one particular source...like:
    In this part:

     if (!isGPSEnabled && !isNetworkEnabled) {
                // no network provider is enabled
            }    
    

    just separate it into two different if(s) and code accordingly. As of now, nothing happens here so you wouldn't know if both are disabled unless you check it externally.

    Suggestion: Try the LocationClient which uses GooglePlayServices for Retrieving Current Location . I have found it more reliable and useful. Check this Fused Location Provider example, setting LocationRequest object according to your requirement is the key.

    Another update: just came across: useful ques on stack overflow - Good way of getting the users location


    Update for anybody looking up this question/answer
    Regarding the suggestion of LocationClient;
    LocationClient is no longer found under com.google.android.gms.location, refer:
    Android play services 6.5: LocationClient is missing

    0 讨论(0)
提交回复
热议问题