android - servicios - La API de ubicación del servicio Google Play devuelve una ubicación incorrecta algunas veces
servicios de google play se detuvo (6)
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 de captura - 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 de captura - 2017-01-04 09:20:01 )
a veces su búsqueda errónea declarada de india como usuario es de gujrat, luego 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
Tuve el mismo problema en Pune, India. El dispositivo utilizado para probar era la tableta Swipe,
Solución : guardo la última latitud y longitud y el tiempo de actualización , cuando la próxima actualización de latitud y longitud, calcule la distancia entre esas dos ubicaciones, si la distancia es superior a 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
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.
Es posible que también desee estudiar la implementación de un filtro de Kalman básico en su aplicación para mantener y actualizar una estimación de la ubicación del usuario. Buena suerte.
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 que si está usando GoogleApiClient
, estoy usando actualmente, hay una nueva clase para la ubicación fusionada FusedLocationProvider , puede 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. Puede consultar este documento para conocer un nuevo comportamiento.
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 de GoogleLocation.GoogleLocationCallback en qué actividad o fragmento obtiene 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);
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();
La ubicación que obtienes de la API tendrá precisión 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.