Pregunta La API de ubicación del servicio Google Play devuelve una ubicación incorrecta algunas veces


Tenemos una aplicación que captura la ubicación del usuario mediante la API de ubicación del servicio de Google Play para cada transacción, como un terreno geográfico, al realizar un pedido, etc.

Después de capturar estas ubicaciones desde un dispositivo móvil, lo sincronizaremos con el servidor y lo mostraremos en el panel de la web.

Hemos notado que en pocos casos la transacción capturada en pocos segundos tiene resultados de ubicación de distancia variada.


Ejemplo:
La ubicación del usuario estará en

Mandsaur, Madhya Pradesh, India, Asia
  (Latitud - 24.057291, Longitud - 75.0970672, Fecha capturada - 2017-01-04 09:19:48)

Pero las transacciones posteriores tendrán la ubicación de

París  que está a 6772 km
(Latitud - 48.8581074, Longitud - 2.3525187, Fecha capturada - 2017-01-04 09:20:01)


a veces su búsqueda incorrecta de India como el usuario es de Gujrat, entonces la localización de Bihar, Maharastra, Kuwait (de la India) es realmente un dolor de cabeza para el desarrollador indio 


Como esto sucede sin interferencia del usuario y sin aplicaciones de ubicación simuladas instaladas en el dispositivo del usuario.

¿Alguien puede explicar por qué sucede esto y cómo podríamos evitar estos escenarios?


NOTA:
Estas ubicaciones de transacción se capturan generalmente en campos abiertos con GPS encendido y configurado en modo de alta precisión


32
2018-02-13 06:48


origen


Respuestas:


La ubicación que obtienes de la API tendrá exactitud en metros También debe verificar la antigüedad de la ubicación.

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

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

La gente generalmente descarta la ubicación si la precisión es mayor a 50 o 100 m.


¿Por qué sucede esto?

El GPS del dispositivo tarda un tiempo en encontrar satélites y obtener la señal. Además, la API intentará determinar su ubicación en función de su red. Es un tipo de salto entre la red y el GPS, hasta que el GPS proporciona algunos datos precisos.


¿Cómo evitar esto?

En su oyente de ubicación, verifique la precisión y espere hasta que tenga una mejor precisión.


8
2017-08-23 15:36



Para la ubicación apus fusionada de Google puedes usar el código a continuación

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);
    }
}

Ahora implementa la devolución de llamada GoogleLocation.GoogleLocationCallback en qué actividad o fragmento busca la ubicación y luego escriba el código a continuación en qué actividad o fragmento obtiene la ubicación

googleLocation = new GoogleLocation(this);
googleLocation.setGoogleLocationCallback(this);

3
2017-08-29 10:05



La mejor manera de resolver esto, filtrando los resultados. La probabilidad de una ubicación correcta devuelta por un servicio Fuse es del 67%, lo que significa que puede obtener una ubicación incorrecta en 1/3.

Debe comparar la ubicación anterior (o más de una, para estar seguro, mantenerlas en una lista) con la actual antes de obtener la ubicación. Si hay una diferencia notible, no use la última.

Nota: no guarde las ubicaciones de los usuarios en un archivo o carpeta, va en contra de la política de privacidad, simplemente compare con lastKnownLocation o las ubicaciones recibidas en la sesión actual.

Otra idea es si estás usando GoogleApiClient, actualmente estoy usando, hay una nueva clase para ubicación fusionada FusedLocationProvider, puedes verificarlo.

Además, hasta donde yo entendí, pusieron 4 límites de recuperación de ubicación por hora para dispositivos con Android 8.0 (API de nivel 26) y posteriores. Puedes comprobar este documento para un nuevo comportamiento.


2
2017-08-27 06:29



El sitio oficial para desarrolladores de Android tiene una página dedicada a Estrategias de ubicación para aplicaciones exitosas de Android Puedes leer más allí, así que sin entrar en muchos detalles, la documentación oficial establece lo siguiente ...

Es de esperar que la corrección de ubicación más reciente sea la más precisa. Sin embargo, como la precisión de una corrección de ubicación varía, la corrección más reciente no siempre es la mejor. Debe incluir lógica para elegir arreglos de ubicación basados ​​en varios criterios. Los criterios también varían según los casos de uso de la aplicación y las pruebas de campo.

Aquí hay algunos pasos que puede seguir para validar la precisión de una corrección de ubicación:

  • Compruebe si la ubicación recuperada es significativamente más nueva que la estimación anterior.
  • Verifique si la exactitud reclamada por la ubicación es mejor o peor que la estimación anterior.
  • Verifique de qué proveedor es la nueva ubicación y determine si confía más en ella.

También es posible que desee considerar la implementación de un básico Filtro de Kalman en su aplicación para mantener y actualizar una estimación de la ubicación del usuario. Buena suerte.


2
2017-08-29 15:42



Tuve el mismo problema en Pune, India. El dispositivo utilizado para probar era la tableta Swipe,

Solución : sigo última latitud y longitud y tiempo de actualización, cuando se actualicen la siguiente latitud y longitud, calcule la distancia entre esas dos ubicaciones, si la distancia es mayor que 100 KM, entonces no contará.

Método que utilicé para calcular la distancia

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);
}    

Por qué sucede

En el dispositivo Android hay 2 opciones para obtener la ubicación

  • GPS
  • Internet

GPS (LocationManager.GPS_PROVIDER): es lento en comparación con Internet, pero será más preciso que Internet, en áreas remotas La conexión GPS será más lenta y, a veces, difícil de conectar.

Internet (LocationManager.NETWORK_PROVIDER): es mucho más rápido que el GPS, pero es menos preciso que el GPS

Si el GPS no está disponible y necesita la ubicación actual, LocationManager le dará los datos disponibles, que se obtienen de Internet. (en este caso, también puede verificar el proveedor de ubicación).

Perdón por mi mal inglés, si es difícil de entender, por favor comente


1
2017-08-23 09:31



Puedes usar esto:

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;
    }

}

Me gusta esto en tu actividad

GPSTracker gps = new GPSTracker(this);

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

0
2017-08-29 21:12