web-dev-qa-db-fra.com

L'API de localisation du service Google Play renvoie parfois un mauvais emplacement

Nous avons une application qui capture la position de l'utilisateur à l'aide de l'API de localisation de service Google Play pour chaque transaction comme Geotag land, lors de la commande, etc.

Après avoir capturé ces emplacements depuis un mobile, nous le synchroniserons avec le serveur et l'afficherons dans le tableau de bord Web.

Nous avons remarqué que dans quelques cas, une transaction capturée en quelques secondes avait des résultats de localisation de distance variée.


Exemple:
L'emplacement de l'utilisateur sera dans

Mandsaur, Madhya Pradesh, Inde, Asie
(Latitude - 24.057291, Longitude - 75.0970672, Date de capture - 2017-01-04 09:19:48).

Mais les transactions ultérieures auront lieu

Paris qui est à 6772 km
(Latitude - 48.8581074, Longitude - 2.3525187, Date de capture - 2017-01-04 09:20:01)


Parfois, sa récupération est incorrecte indiquée Inde comme l'utilisateur vient de Gujrat, puis la localisation de Bihar, Maharastra, Koweït (hors de l'Inde), c'est vraiment un casse-tête pour le développeur indien


Comme cela se produit sans interférence de l'utilisateur et aucune application de localisation fictive installée sur l'appareil de l'utilisateur.

Quelqu'un peut-il expliquer pourquoi cela se produit et comment éviter ces scénarios?


REMARQUE:
Ces emplacements de transaction sont généralement capturés dans des champs ouverts avec le GPS activé et réglé en mode haute précision

34
Vinay Kashyap T S

L'emplacement que vous obtenez à partir de l'API aura précision en mètres. Vous devez également vérifier l'âge de l'emplacement.

https://developer.Android.com/reference/Android/location/Location.html#getAccuracy ()

https://developer.Android.com/reference/Android/location/Location.html#getTime ()

Les gens rejettent généralement l'emplacement si la précision est supérieure à 50 ou 100 m.


Pourquoi cela se produit-il?

Il faut du temps au GPS de l'appareil pour trouver des satellites et obtenir le signal. De plus, l'API tentera de déterminer votre emplacement en fonction de votre réseau. Il passe en quelque sorte du réseau au GPS, jusqu'à ce que le GPS fournisse des données précises.


Comment éviter cela?

Dans votre écouteur de localisation, vérifiez l'exactitude et attendez d'avoir une meilleure précision.

10
Froyo

Le site officiel des développeurs Android a une page dédiée à Stratégies de localisation pour les applications réussies Android. Vous pouvez en lire plus ici, donc sans entrant dans les détails, la documentation officielle indique ce qui suit ...

Vous pouvez vous attendre à ce que la correction d'emplacement la plus récente soit la plus précise. Cependant, étant donné que la précision d'un correctif d'emplacement varie, le correctif le plus récent n'est pas toujours le meilleur. Vous devez inclure une logique pour choisir les correctifs d'emplacement en fonction de plusieurs critères. Les critères varient également en fonction des cas d'utilisation de l'application et des tests sur le terrain.

Voici quelques étapes à suivre pour valider la précision d'un correctif d'emplacement:

  • Vérifiez si l'emplacement récupéré est beaucoup plus récent que l'estimation précédente.
  • Vérifiez si la précision revendiquée par l'emplacement est meilleure ou pire que l'estimation précédente.
  • Vérifiez de quel fournisseur provient le nouvel emplacement et déterminez si vous lui faites davantage confiance.

Vous pouvez également envisager d'implémenter une base Kalman Filter dans votre application pour maintenir et mettre à jour une estimation de l'emplacement de l'utilisateur. Bonne chance.

4
v1bri

Pour Google api fusionné de localisation, vous pouvez utiliser le code ci-dessous

package com.hydrometcloud.location;

import Android.app.Activity;
import Android.content.Context;
import Android.content.IntentSender;
import Android.location.Location;
import Android.os.Bundle;
import Android.support.annotation.NonNull;
import Android.support.annotation.Nullable;
import Android.util.Log;

import com.google.Android.gms.common.ConnectionResult;
import com.google.Android.gms.common.api.GoogleApiClient;
import com.google.Android.gms.common.api.PendingResult;
import com.google.Android.gms.common.api.ResultCallback;
import com.google.Android.gms.common.api.Status;
import com.google.Android.gms.location.LocationListener;
import com.google.Android.gms.location.LocationRequest;
import com.google.Android.gms.location.LocationServices;
import com.google.Android.gms.location.LocationSettingsRequest;
import com.google.Android.gms.location.LocationSettingsResult;
import com.google.Android.gms.location.LocationSettingsStatusCodes;


public class GoogleLocation implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener,
        ResultCallback<LocationSettingsResult> {

    private LocationSettingsRequest mLocationSettingsRequest;
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
    private String TAG = "GoogleLocation";

    private Context context;
    private long UPDATE_INTERVAL = 10 * 1000;  /* 10 secs */
    private long FASTEST_INTERVAL = 2000; /* 2 sec */
    private GoogleLocationCallback googleLocationCallback;

    private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
    public static final int REQUEST_CHECK_SETTINGS = 0x1;

    public GoogleLocation(Context context) {
        this.context = context;
        setUpLocation();
    }

    public void setGoogleLocationCallback(GoogleLocationCallback googleLocationCallback) {
        this.googleLocationCallback = googleLocationCallback;
    }

    private void setUpLocation() {

        mGoogleApiClient = new GoogleApiClient.Builder(context.getApplicationContext())
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

        // Create the LocationRequest object
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(UPDATE_INTERVAL)        // 10 seconds, in milliseconds
                .setFastestInterval(FASTEST_INTERVAL); // 1 second, in milliseconds

        locationEnable();
    }

    public void googleClientConnect() {
        mGoogleApiClient.connect();
    }

    public void googleClientDisConnect() {
        if (mGoogleApiClient.isConnected()) {
            mGoogleApiClient.unregisterConnectionCallbacks(this);
            mGoogleApiClient.unregisterConnectionFailedListener(this);
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            mGoogleApiClient.disconnect();
            mGoogleApiClient = null;
        }
    }

    private void locationEnable() {
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
        builder.addLocationRequest(mLocationRequest);
        mLocationSettingsRequest = builder.build();
        checkLocationSettings();
    }

    private void checkLocationSettings() {
        PendingResult<LocationSettingsResult> result =
                LocationServices.SettingsApi.checkLocationSettings(
                        mGoogleApiClient,
                        mLocationSettingsRequest
                );
        result.setResultCallback(this);
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if (location == null) {
            updateLocation();
        } else {
            handleNewLocation(location);
        }
    }

    private void handleNewLocation(Location location) {

        double currentLatitude = location.getLatitude();
        double currentLongitude = location.getLongitude();

        Log.e(TAG, "---currentLatitude--" + currentLatitude);
        Log.e(TAG, "---currentLongitude--" + currentLongitude);

        if (googleLocationCallback != null) {
            googleLocationCallback.updateLocationListner(currentLatitude, currentLongitude);
        }

    }

    public void updateLocation() {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
                     /*
         * Google Play services can resolve some errors it detects.
         * If the error has a resolution, try sending an Intent to
         * start a Google Play services activity that can resolve
         * error.
         */
        if (connectionResult.hasResolution()) {
            try {
                // Start an Activity that tries to resolve the error
                connectionResult.startResolutionForResult((Activity) context, CONNECTION_FAILURE_RESOLUTION_REQUEST);
                /*
                 * Thrown if Google Play services canceled the original
                 * PendingIntent
                 */
            } catch (IntentSender.SendIntentException e) {
                // Log the error
                e.printStackTrace();
            }
        } else {
            /*
             * If no resolution is available, display a dialog to the
             * user with the error.
             */
            Log.e(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
        }
    }

    @Override
    public void onResult(@NonNull LocationSettingsResult locationSettingsResult) {
        final Status status = locationSettingsResult.getStatus();
        switch (status.getStatusCode()) {
            case LocationSettingsStatusCodes.SUCCESS:
                Log.e(TAG, "All location settings are satisfied.");
                break;
            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                Log.e(TAG, "Location settings are not satisfied. Show the user a dialog to" +
                        "upgrade location settings ");

                try {
                    // Show the dialog by calling startResolutionForResult(), and check the result
                    // in onActivityResult().
                    status.startResolutionForResult((Activity) context, REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "PendingIntent unable to execute request.");
                }
                break;
            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                Log.e(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog " +
                        "not created.");
                break;
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        handleNewLocation(location);
    }

    public interface GoogleLocationCallback {
        void updateLocationListner(double latitude, double longitude);
    }
}

Maintenant, vous implémentez le rappel GoogleLocation.GoogleLocationCallback sur quelle activité ou fragment vous récupérez l'emplacement et après cela, écrivez ci-dessous le code sur quelle activité ou fragment vous obtenez l'emplacement

googleLocation = new GoogleLocation(this);
googleLocation.setGoogleLocationCallback(this);
3
Darshan Mistry

Le meilleur moyen de résoudre ce problème en filtrant les résultats. La probabilité d'un emplacement correct renvoyé par un service Fuse est de 67%, ce qui signifie que vous pouvez obtenir un mauvais emplacement au 1/3.

Vous devez comparer l'emplacement précédent (ou plus d'un pour être sûr, conservez-les dans une liste) avec l'emplacement actuel avant d'obtenir l'emplacement. S'il y a une différence notable, n'utilisez pas la dernière.

Remarque: ne sauvegardez pas les emplacements des utilisateurs dans un fichier ou un dossier, c'est contraire à la politique de confidentialité, comparez simplement avec lastKnownLocation ou les emplacements reçus dans la session en cours.

Une autre idée est que si vous utilisez GoogleApiClient, j'utilise actuellement, il y a une nouvelle classe pour l'emplacement fusionné FusedLocationProvider , vous pouvez le vérifier.

Aussi loin que je sache, ils ont mis une limite de récupération de 4 emplacements par heure pour les appareils avec Android 8.0 (API niveau 26) et plus tard. Vous pouvez vérifier ce document pour les nouveaux comportement.

2
Thracian

J'ai eu le même problème à Pune, en Inde. L'appareil utilisé pour tester était Swipe tablet,

Solution: je garde dernière latitude et longitude et heure de mise à jour, lors de la prochaine mise à jour de latitude et longitude, calculez la distance entre ces deux emplacements, si la distance est supérieure à 100 KM, alors cela ne comptera pas.

Méthode i utilisée pour calculer la distance

public static double calculateDistance(double lat1,double lon1,double lat2,double lon2) {

    double theta = lon1 - lon2;
    double dist = Math.sin(deg2rad(lat1))
            * Math.sin(deg2rad(lat2))
            + Math.cos(deg2rad(lat1))
            * Math.cos(deg2rad(lat2))
            * Math.cos(deg2rad(theta));
    dist = Math.acos(dist);
    dist = rad2deg(dist);
    dist = dist * 60 * 1.1515;
    return (dist);
}    

Pourquoi ça arrive

Sur Android appareil, il y a 2 options pour obtenir l'emplacement

  • GPS
  • L'Internet

GPS (LocationManager.GPS_PROVIDER): est lent comparé à Internet, mais il sera plus précis qu'Internet, dans les régions éloignées, la connexion GPS sera plus lente et parfois difficile à connecter.

Internet (LocationManager.NETWORK_PROVIDER): est beaucoup plus rapide que le GPS, mais moins précis que le GPS

Si le GPS est inaccessible et que vous avez besoin de votre position actuelle, LocationManager vous donnera les données disponibles, qui sont récupérées sur Internet. (dans ce cas, vous pouvez également vérifier le fournisseur de localisation.)

1
Anu Martin

Vous pouvez utiliser ceci:

package com.amolood.news.manager;

/**
 * Created by nasnasa on 14/02/2017.
 */

import Android.app.AlertDialog;
import Android.app.Service;
import Android.content.Context;
import Android.content.DialogInterface;
import Android.content.Intent;
import Android.location.Location;
import Android.location.LocationListener;
import Android.location.LocationManager;
import Android.os.Bundle;
import Android.os.IBinder;
import Android.provider.Settings;
import Android.util.Log;


/**
 * Created by nasnasa on 14/01/2017.
 */

public class GPSTracker extends Service implements LocationListener {

    private final Context mContext;

    // flag for GPS status
    boolean isGPSEnabled = false;

    // flag for network status
    boolean isNetworkEnabled = false;

    // flag for GPS status
    boolean canGetLocation = false;

    Location location; // location
    double latitude; // latitude
    double longitude; // longitude

    // The minimum distance to change Updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters

    // The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute

    // Declaring a Location Manager
    protected LocationManager locationManager;

    public GPSTracker(Context context) {
        this.mContext = context;
        getLocation();
    }

    public Location getLocation() {
        try {
            locationManager = (LocationManager) mContext
                    .getSystemService(LOCATION_SERVICE);

            // getting GPS status
            isGPSEnabled = locationManager
                    .isProviderEnabled(LocationManager.GPS_PROVIDER);

            // getting network status
            isNetworkEnabled = locationManager
                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled) {
                // no network provider is enabled
            } else {
                this.canGetLocation = true;
                // First get location from Network Provider
                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();
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return location;
    }

    /**
     * Stop using GPS listener
     * Calling this function will stop using GPS in your app
     * */
    public void stopUsingGPS(){
        if(locationManager != null){
            locationManager.removeUpdates(GPSTracker.this);
        }
    }

    /**
     * Function to get latitude
     * */
    public double getLatitude(){
        if(location != null){
            latitude = location.getLatitude();
        }

        // return latitude
        return latitude;
    }

    /**
     * Function to get longitude
     * */
    public double getLongitude(){
        if(location != null){
            longitude = location.getLongitude();
        }

        // return longitude
        return longitude;
    }

    /**
     * Function to check GPS/wifi enabled
     * @return boolean
     * */
    public boolean canGetLocation() {
        return this.canGetLocation;
    }

    /**
     * Function to show settings alert dialog
     * On pressing Settings button will lauch Settings Options
     * */
    public void showSettingsAlert(){
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

        // Setting Dialog Title
        alertDialog.setTitle("GPS is settings");

        // Setting Dialog Message
        alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");

        // On pressing Settings button
        alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog,int which) {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                mContext.startActivity(intent);
            }
        });

        // on pressing cancel button
        alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        // Showing Alert Message
        alertDialog.show();
    }

    @Override
    public void onLocationChanged(Location location) {
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

}

comme ça sur votre activité

GPSTracker gps = new GPSTracker(this);

gps.getlocation();
double latitude = gps.getLatitude();
double longitude = gps.getLongitude();
0
ABDALRAHMAN MOLOOD