ubicacion studio por obtener localizar google encontrar dispositivo celular android geolocation android-location

por - obtener ubicacion android studio 2018



Buena forma de conseguir la ubicaciĆ³n del usuario en Android. (12)

El problema:

Obtener la ubicación actual del usuario dentro de un umbral lo antes posible y al mismo tiempo conservar la batería.

Por qué el problema es un problema:

En primer lugar, Android tiene dos proveedores; Red y GPS. A veces la red es mejor y otras veces el GPS es mejor.

Por "mejor" me refiero a la relación velocidad / precisión.
Estoy dispuesto a sacrificar unos pocos metros de precisión si puedo obtener la ubicación casi instantáneamente y sin encender el GPS.

En segundo lugar, si solicita actualizaciones para cambios de ubicación, no se envía nada si la ubicación actual es estable.

Google tiene un ejemplo para determinar la "mejor" ubicación aquí: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
Pero creo que no es tan bueno como debería o podría ser.

Estoy un poco confundido por qué Google no tiene una API normalizada para la ubicación, el desarrollador no debería tener que preocuparse por la ubicación, solo debe especificar qué desea y el teléfono debe elegir por usted.

Lo que necesito ayuda con:

Necesito encontrar una buena manera de determinar la "mejor" ubicación, tal vez a través de alguna heurística o tal vez a través de una biblioteca de terceros.

Esto no significa determinar el mejor proveedor!
Probablemente voy a usar a todos los proveedores y escogeré a los mejores.

Antecedentes de la aplicación:

La aplicación recopilará la ubicación del usuario en un intervalo fijo (digamos cada 10 minutos aproximadamente) y la enviará a un servidor.
La aplicación debe conservar tanta batería como sea posible y la ubicación debe tener una precisión de X (50-100?) Metros.

El objetivo es luego poder trazar la ruta del usuario durante el día en un mapa, por lo que necesito suficiente precisión para eso.

Misceláneo

¿Cuáles crees que son valores razonables en las precisiones deseadas y aceptadas?
He estado usando 100 m como se acepta y 30 m como se desea, ¿es mucho pedir?
Me gustaría poder trazar la ruta del usuario en un mapa más adelante.
¿Es 100m por deseado y 500m por mejor aceptado?

Además, ahora mismo tengo el GPS encendido por un máximo de 60 segundos por actualización de ubicación, ¿es esto demasiado corto para obtener una ubicación si está en interiores con una precisión de quizás 200 m?

Este es mi código actual, se agradece cualquier comentario (aparte de la falta de verificación de errores que es TODO):

protected void runTask() { final LocationManager locationManager = (LocationManager) context .getSystemService(Context.LOCATION_SERVICE); updateBestLocation(locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER)); updateBestLocation(locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER)); if (getLocationQuality(bestLocation) != LocationQuality.GOOD) { Looper.prepare(); setLooper(Looper.myLooper()); // Define a listener that responds to location updates LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { updateBestLocation(location); if (getLocationQuality(bestLocation) != LocationQuality.GOOD) return; // We''re done Looper l = getLooper(); if (l != null) l.quit(); } public void onProviderEnabled(String provider) {} public void onProviderDisabled(String provider) {} public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub Log.i("LocationCollector", "Fail"); Looper l = getLooper(); if (l != null) l.quit(); } }; // Register the listener with the Location Manager to receive // location updates locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 1, locationListener, Looper.myLooper()); locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 1, locationListener, Looper.myLooper()); Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run() { Looper l = getLooper(); if (l != null) l.quit(); // Log.i("LocationCollector", // "Stopping collector due to timeout"); } }, MAX_POLLING_TIME); Looper.loop(); t.cancel(); locationManager.removeUpdates(locationListener); setLooper(null); } if (getLocationQuality(bestLocation) != LocationQuality.BAD) sendUpdate(locationToString(bestLocation)); else Log.w("LocationCollector", "Failed to get a location"); } private enum LocationQuality { BAD, ACCEPTED, GOOD; public String toString() { if (this == GOOD) return "Good"; else if (this == ACCEPTED) return "Accepted"; else return "Bad"; } } private LocationQuality getLocationQuality(Location location) { if (location == null) return LocationQuality.BAD; if (!location.hasAccuracy()) return LocationQuality.BAD; long currentTime = System.currentTimeMillis(); if (currentTime - location.getTime() < MAX_AGE && location.getAccuracy() <= GOOD_ACCURACY) return LocationQuality.GOOD; if (location.getAccuracy() <= ACCEPTED_ACCURACY) return LocationQuality.ACCEPTED; return LocationQuality.BAD; } private synchronized void updateBestLocation(Location location) { bestLocation = getBestLocation(location, bestLocation); } // Pretty much an unmodified version of googles example protected Location getBestLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return location; } if (location == null) return currentBestLocation; // 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 location; // If the new location is more than two minutes older, it must be // worse } else if (isSignificantlyOlder) { return currentBestLocation; } // 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 location; } else if (isNewer && !isLessAccurate) { return location; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return location; } return bestLocation; } /** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) { return provider2 == null; } return provider1.equals(provider2); }


Actualmente estoy usando ya que esto es confiable para obtener la ubicación y calcular la distancia para mi aplicación ... Estoy usando esto para mi aplicación de taxi.

use la API de fusión que el desarrollador de Google ha desarrollado con la fusión del Sensor GPS, el Magnetómetro, el Acelerómetro y el uso de Wifi o la ubicación de la celda para calcular o estimar la ubicación. También es capaz de dar actualizaciones de ubicación también dentro del edificio con precisión. para obtener detalles, consulte el enlace https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi

import android.app.Activity; import android.location.Location; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class MainActivity extends Activity implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static final long ONE_MIN = 500; private static final long TWO_MIN = 500; private static final long FIVE_MIN = 500; private static final long POLLING_FREQ = 1000 * 20; private static final long FASTEST_UPDATE_FREQ = 1000 * 5; private static final float MIN_ACCURACY = 1.0f; private static final float MIN_LAST_READ_ACCURACY = 1; private LocationRequest mLocationRequest; private Location mBestReading; TextView tv; private GoogleApiClient mGoogleApiClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!servicesAvailable()) { finish(); } setContentView(R.layout.activity_main); tv= (TextView) findViewById(R.id.tv1); mLocationRequest = LocationRequest.create(); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationRequest.setInterval(POLLING_FREQ); mLocationRequest.setFastestInterval(FASTEST_UPDATE_FREQ); mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(LocationServices.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); if (mGoogleApiClient != null) { mGoogleApiClient.connect(); } } @Override protected void onResume() { super.onResume(); if (mGoogleApiClient != null) { mGoogleApiClient.connect(); } } @Override protected void onPause() {d super.onPause(); if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } } tv.setText(location + ""); // Determine whether new location is better than current best // estimate if (null == mBestReading || location.getAccuracy() < mBestReading.getAccuracy()) { mBestReading = location; if (mBestReading.getAccuracy() < MIN_ACCURACY) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); } } } @Override public void onConnected(Bundle dataBundle) { // Get first reading. Get additional location updates if necessary if (servicesAvailable()) { // Get best last location measurement meeting criteria mBestReading = bestLastKnownLocation(MIN_LAST_READ_ACCURACY, FIVE_MIN); if (null == mBestReading || mBestReading.getAccuracy() > MIN_LAST_READ_ACCURACY || mBestReading.getTime() < System.currentTimeMillis() - TWO_MIN) { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); //Schedule a runnable to unregister location listeners @Override public void run() { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, MainActivity.this); } }, ONE_MIN, TimeUnit.MILLISECONDS); } } } @Override public void onConnectionSuspended(int i) { } private Location bestLastKnownLocation(float minAccuracy, long minTime) { Location bestResult = null; float bestAccuracy = Float.MAX_VALUE; long bestTime = Long.MIN_VALUE; // Get the best most recent location currently available Location mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); //tv.setText(mCurrentLocation+""); if (mCurrentLocation != null) { float accuracy = mCurrentLocation.getAccuracy(); long time = mCurrentLocation.getTime(); if (accuracy < bestAccuracy) { bestResult = mCurrentLocation; bestAccuracy = accuracy; bestTime = time; } } // Return best reading or null if (bestAccuracy > minAccuracy || bestTime < minTime) { return null; } else { return bestResult; } } @Override public void onConnectionFailed(ConnectionResult connectionResult) { } private boolean servicesAvailable() { int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (ConnectionResult.SUCCESS == resultCode) { return true; } else { GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0).show(); return false; } } }


Busqué en Internet una respuesta actualizada (el año pasado) utilizando los últimos métodos de extracción de ubicación sugeridos por google (para usar FusedLocationProviderClient). Finalmente aterricé en esto:

https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates

Creé un nuevo proyecto y copié la mayor parte de este código. Auge. Funciona. Y creo que sin ninguna línea desaprobada.

Además, el simulador no parece tener una ubicación GPS, que yo sepa. Llegó hasta el punto de informar esto en el registro: "Se cumplen todos los ajustes de ubicación".

Y, por último, en caso de que quisiera saber (lo hice), NO necesita una clave de API de google maps desde la consola de desarrolladores de Google, si todo lo que desea es la ubicación del GPS.

También es útil su tutorial. Pero quería un ejemplo completo de código / tutorial de una página, y eso. Sus tutoriales se acumulan, pero son confusos cuando eres nuevo en esto porque no sabes qué piezas necesitas de páginas anteriores.

https://developer.android.com/training/location/index.html

Y finalmente, recuerda cosas como esta:

No solo tuve que modificar el mainActivity.Java. También tuve que modificar Strings.xml, androidmanifest.xml, Y el build.gradle correcto. Y también tu activity_Main.xml (pero esa parte fue fácil para mí).

Necesitaba agregar dependencias como esta: implementación ''com.google.android.gms: play-services-location: 11.8.0'', y actualizar la configuración de mi SDK de Android Studio para incluir los servicios de Google Play. (la configuración de archivos aparece en la configuración del sistema android SDK SDK Tools comprueba los servicios de Google Play).

actualización: el simulador de Android parecía tener una ubicación y eventos de cambio de ubicación (cuando cambié el valor en la configuración del sim). Pero mis mejores y primeros resultados fueron en un dispositivo real. Así que probablemente sea más fácil probar en dispositivos reales.


En mi experiencia, he encontrado que lo mejor es ir con la solución GPS a menos que no esté disponible. No sé mucho acerca de otros proveedores de ubicación, pero sé que para el GPS hay algunos trucos que se pueden usar para dar una medida de precisión del ghetto. La altitud suele ser un signo, por lo que puede comprobar valores ridículos. Existe la medida de precisión en las correcciones de ubicación de Android. Además, si puede ver la cantidad de satélites utilizados, esto también puede indicar la precisión.

Una forma interesante de obtener una mejor idea de la precisión podría ser solicitar un conjunto de soluciones muy rápidamente, como ~ 1 / seg durante 10 segundos y luego dormir durante uno o dos minutos. Una charla en la que he estado me ha llevado a creer que, de todos modos, algunos dispositivos Android harán esto. Luego eliminaría los valores atípicos (he escuchado mencionar el filtro de Kalman aquí) y usará algún tipo de estrategia de centrado para obtener una única solución.

Obviamente, la profundidad a la que llegas aquí depende de lo difíciles que sean tus requisitos. Si tiene un requisito particularmente estricto para obtener la MEJOR ubicación posible, creo que encontrará que la ubicación de la red y el GPS son tan similares como las manzanas y naranjas. Además, el GPS puede ser muy diferente de un dispositivo a otro.


Esta es mi solución que funciona bastante bien:

private Location bestLocation = null; private Looper looper; private boolean networkEnabled = false, gpsEnabled = false; private synchronized void setLooper(Looper looper) { this.looper = looper; } private synchronized void stopLooper() { if (looper == null) return; looper.quit(); } @Override protected void runTask() { final LocationManager locationManager = (LocationManager) service .getSystemService(Context.LOCATION_SERVICE); final SharedPreferences prefs = getPreferences(); final int maxPollingTime = Integer.parseInt(prefs.getString( POLLING_KEY, "0")); final int desiredAccuracy = Integer.parseInt(prefs.getString( DESIRED_KEY, "0")); final int acceptedAccuracy = Integer.parseInt(prefs.getString( ACCEPTED_KEY, "0")); final int maxAge = Integer.parseInt(prefs.getString(AGE_KEY, "0")); final String whichProvider = prefs.getString(PROVIDER_KEY, "any"); final boolean canUseGps = whichProvider.equals("gps") || whichProvider.equals("any"); final boolean canUseNetwork = whichProvider.equals("network") || whichProvider.equals("any"); if (canUseNetwork) networkEnabled = locationManager .isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (canUseGps) gpsEnabled = locationManager .isProviderEnabled(LocationManager.GPS_PROVIDER); // If any provider is enabled now and we displayed a notification clear it. if (gpsEnabled || networkEnabled) removeErrorNotification(); if (gpsEnabled) updateBestLocation(locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER)); if (networkEnabled) updateBestLocation(locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER)); if (desiredAccuracy == 0 || getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge, bestLocation) != LocationQuality.GOOD) { // Define a listener that responds to location updates LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { updateBestLocation(location); if (desiredAccuracy != 0 && getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge, bestLocation) == LocationQuality.GOOD) stopLooper(); } public void onProviderEnabled(String provider) { if (isSameProvider(provider, LocationManager.NETWORK_PROVIDER))networkEnabled =true; else if (isSameProvider(provider, LocationManager.GPS_PROVIDER)) gpsEnabled = true; // The user has enabled a location, remove any error // notification if (canUseGps && gpsEnabled || canUseNetwork && networkEnabled) removeErrorNotification(); } public void onProviderDisabled(String provider) { if (isSameProvider(provider, LocationManager.NETWORK_PROVIDER))networkEnabled=false; else if (isSameProvider(provider, LocationManager.GPS_PROVIDER)) gpsEnabled = false; if (!gpsEnabled && !networkEnabled) { showErrorNotification(); stopLooper(); } } public void onStatusChanged(String provider, int status, Bundle extras) { Log.i(LOG_TAG, "Provider " + provider + " statusChanged"); if (isSameProvider(provider, LocationManager.NETWORK_PROVIDER)) networkEnabled = status == LocationProvider.AVAILABLE || status == LocationProvider.TEMPORARILY_UNAVAILABLE; else if (isSameProvider(provider, LocationManager.GPS_PROVIDER)) gpsEnabled = status == LocationProvider.AVAILABLE || status == LocationProvider.TEMPORARILY_UNAVAILABLE; // None of them are available, stop listening if (!networkEnabled && !gpsEnabled) { showErrorNotification(); stopLooper(); } // The user has enabled a location, remove any error // notification else if (canUseGps && gpsEnabled || canUseNetwork && networkEnabled) removeErrorNotification(); } }; if (networkEnabled || gpsEnabled) { Looper.prepare(); setLooper(Looper.myLooper()); // Register the listener with the Location Manager to receive // location updates if (canUseGps) locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 1, locationListener, Looper.myLooper()); if (canUseNetwork) locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 1, locationListener, Looper.myLooper()); Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run() { stopLooper(); } }, maxPollingTime * 1000); Looper.loop(); t.cancel(); setLooper(null); locationManager.removeUpdates(locationListener); } else // No provider is enabled, show a notification showErrorNotification(); } if (getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge, bestLocation) != LocationQuality.BAD) { sendUpdate(new Event(EVENT_TYPE, locationToString(desiredAccuracy, acceptedAccuracy, maxAge, bestLocation))); } else Log.w(LOG_TAG, "LocationCollector failed to get a location"); } private synchronized void showErrorNotification() { if (notifId != 0) return; ServiceHandler handler = service.getHandler(); NotificationInfo ni = NotificationInfo.createSingleNotification( R.string.locationcollector_notif_ticker, R.string.locationcollector_notif_title, R.string.locationcollector_notif_text, android.R.drawable.stat_notify_error); Intent intent = new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); ni.pendingIntent = PendingIntent.getActivity(service, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); Message msg = handler.obtainMessage(ServiceHandler.SHOW_NOTIFICATION); msg.obj = ni; handler.sendMessage(msg); notifId = ni.id; } private void removeErrorNotification() { if (notifId == 0) return; ServiceHandler handler = service.getHandler(); if (handler != null) { Message msg = handler.obtainMessage( ServiceHandler.CLEAR_NOTIFICATION, notifId, 0); handler.sendMessage(msg); notifId = 0; } } @Override public void interrupt() { stopLooper(); super.interrupt(); } private String locationToString(int desiredAccuracy, int acceptedAccuracy, int maxAge, Location location) { StringBuilder sb = new StringBuilder(); sb.append(String.format( "qual=%s time=%d prov=%s acc=%.1f lat=%f long=%f", getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge, location), location.getTime() / 1000, // Millis to // seconds location.getProvider(), location.getAccuracy(), location .getLatitude(), location.getLongitude())); if (location.hasAltitude()) sb.append(String.format(" alt=%.1f", location.getAltitude())); if (location.hasBearing()) sb.append(String.format(" bearing=%.2f", location.getBearing())); return sb.toString(); } private enum LocationQuality { BAD, ACCEPTED, GOOD; public String toString() { if (this == GOOD) return "Good"; else if (this == ACCEPTED) return "Accepted"; else return "Bad"; } } private LocationQuality getLocationQuality(int desiredAccuracy, int acceptedAccuracy, int maxAge, Location location) { if (location == null) return LocationQuality.BAD; if (!location.hasAccuracy()) return LocationQuality.BAD; long currentTime = System.currentTimeMillis(); if (currentTime - location.getTime() < maxAge * 1000 && location.getAccuracy() <= desiredAccuracy) return LocationQuality.GOOD; if (acceptedAccuracy == -1 || location.getAccuracy() <= acceptedAccuracy) return LocationQuality.ACCEPTED; return LocationQuality.BAD; } private synchronized void updateBestLocation(Location location) { bestLocation = getBestLocation(location, bestLocation); } protected Location getBestLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return location; } if (location == null) return currentBestLocation; // 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 location; // If the new location is more than two minutes older, it must be // worse } else if (isSignificantlyOlder) { return currentBestLocation; } // 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 location; } else if (isNewer && !isLessAccurate) { return location; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return location; } return bestLocation; } /** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) return provider2 == null; return provider1.equals(provider2); }


La biblioteca Android-ReactiveLocation es otra biblioteca agradable para manejar la ubicación en Android.

Una pequeña biblioteca que envuelve la API de Google Play Service en los brillantes RxJava Observables reduciendo la repetición al mínimo.

https://github.com/mcharmas/Android-ReactiveLocation


La precisión de la ubicación depende principalmente del proveedor de ubicación utilizado:

  1. GPS: le brindará una precisión de varios metros (suponiendo que tenga recepción GPS)
  2. Wifi - Te dará unos cientos de metros de precisión.
  3. Red celular: obtendrá resultados muy inexactos (he visto una desviación de hasta 4 km ...)

Si lo que busca es la precisión, entonces el GPS es su única opción.

He leído un artículo muy informativo al respecto here .

En cuanto al tiempo de espera del GPS, 60 segundos deberían ser suficientes y, en la mayoría de los casos, incluso demasiado. Creo que 30 segundos están bien ya veces incluso menos de 5 segundos ...

si solo necesita una ubicación, sugeriría que en su método onLocationChanged , una vez que reciba una actualización, anulará el registro del oyente y evitará el uso innecesario del GPS.


Para seleccionar el proveedor de ubicación correcto para su aplicación, puede usar Criteria objetos Criteria :

Criteria myCriteria = new Criteria(); myCriteria.setAccuracy(Criteria.ACCURACY_HIGH); myCriteria.setPowerRequirement(Criteria.POWER_LOW); // let Android select the right location provider for you String myProvider = locationManager.getBestProvider(myCriteria, true); // finally require updates at -at least- the desired rate long minTimeMillis = 600000; // 600,000 milliseconds make 10 minutes locationManager.requestLocationUpdates(myProvider,minTimeMillis,0,locationListener);

Lea la documentación de requestLocationUpdates para obtener más detalles sobre cómo se tienen en cuenta los argumentos:

La frecuencia de notificación se puede controlar utilizando los parámetros minTime y minDistance. Si minTime es mayor que 0, el LocationManager podría descansar durante milisegundos de minTime entre actualizaciones de ubicación para ahorrar energía. Si minDistance es mayor que 0, la ubicación solo se transmitirá si el dispositivo se mueve en los medidores de minDistance. Para obtener notificaciones con la mayor frecuencia posible, establezca ambos parámetros en 0.

Mas pensamientos

  • Puede supervisar la precisión de los objetos de Location.getAccuracy() con Location.getAccuracy() , que devuelve la precisión estimada de la posición en metros.
  • el criterio Criteria.ACCURACY_HIGH debe proporcionarle errores por debajo de 100m, lo que no es tan bueno como puede ser el GPS, pero se ajusta a sus necesidades.
  • También debe supervisar el estado de su proveedor de ubicación y cambiar a otro proveedor si el usuario no lo encuentra o lo deshabilita.
  • El proveedor pasivo también puede ser un buen complemento para este tipo de aplicación: la idea es usar las actualizaciones de ubicación siempre que las solicite otra aplicación y se emita en todo el sistema.

Parece que estamos codificando la misma aplicación ;-)
Aquí está mi implementación actual. Todavía estoy en la fase de prueba beta de mi aplicación de carga de GPS, por lo que podría haber muchas mejoras posibles. Pero parece funcionar bastante bien hasta ahora.

/** * try to get the ''best'' location selected from all providers */ private Location getBestLocation() { Location gpslocation = getLocationByProvider(LocationManager.GPS_PROVIDER); Location networkLocation = getLocationByProvider(LocationManager.NETWORK_PROVIDER); // if we have only one location available, the choice is easy if (gpslocation == null) { Log.d(TAG, "No GPS Location available."); return networkLocation; } if (networkLocation == null) { Log.d(TAG, "No Network Location available"); return gpslocation; } // a locationupdate is considered ''old'' if its older than the configured // update interval. this means, we didn''t get a // update from this provider since the last check long old = System.currentTimeMillis() - getGPSCheckMilliSecsFromPrefs(); boolean gpsIsOld = (gpslocation.getTime() < old); boolean networkIsOld = (networkLocation.getTime() < old); // gps is current and available, gps is better than network if (!gpsIsOld) { Log.d(TAG, "Returning current GPS Location"); return gpslocation; } // gps is old, we can''t trust it. use network location if (!networkIsOld) { Log.d(TAG, "GPS is old, Network is current, returning network"); return networkLocation; } // both are old return the newer of those two if (gpslocation.getTime() > networkLocation.getTime()) { Log.d(TAG, "Both are old, returning gps(newer)"); return gpslocation; } else { Log.d(TAG, "Both are old, returning network(newer)"); return networkLocation; } } /** * get the last known location from a specific provider (network/gps) */ private Location getLocationByProvider(String provider) { Location location = null; if (!isProviderSupported(provider)) { return null; } LocationManager locationManager = (LocationManager) getApplicationContext() .getSystemService(Context.LOCATION_SERVICE); try { if (locationManager.isProviderEnabled(provider)) { location = locationManager.getLastKnownLocation(provider); } } catch (IllegalArgumentException e) { Log.d(TAG, "Cannot acces Provider " + provider); } return location; }

Editar: aquí está la parte que solicita las actualizaciones periódicas de los proveedores de ubicación:

public void startRecording() { gpsTimer.cancel(); gpsTimer = new Timer(); long checkInterval = getGPSCheckMilliSecsFromPrefs(); long minDistance = getMinDistanceFromPrefs(); // receive updates LocationManager locationManager = (LocationManager) getApplicationContext() .getSystemService(Context.LOCATION_SERVICE); for (String s : locationManager.getAllProviders()) { locationManager.requestLocationUpdates(s, checkInterval, minDistance, new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) {} @Override public void onProviderEnabled(String provider) {} @Override public void onProviderDisabled(String provider) {} @Override public void onLocationChanged(Location location) { // if this is a gps location, we can use it if (location.getProvider().equals( LocationManager.GPS_PROVIDER)) { doLocationUpdate(location, true); } } }); // //Toast.makeText(this, "GPS Service STARTED", // Toast.LENGTH_LONG).show(); gps_recorder_running = true; } // start the gps receiver thread gpsTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { Location location = getBestLocation(); doLocationUpdate(location, false); } }, 0, checkInterval); } public void doLocationUpdate(Location l, boolean force) { long minDistance = getMinDistanceFromPrefs(); Log.d(TAG, "update received:" + l); if (l == null) { Log.d(TAG, "Empty location"); if (force) Toast.makeText(this, "Current location not available", Toast.LENGTH_SHORT).show(); return; } if (lastLocation != null) { float distance = l.distanceTo(lastLocation); Log.d(TAG, "Distance to last: " + distance); if (l.distanceTo(lastLocation) < minDistance && !force) { Log.d(TAG, "Position didn''t change"); return; } if (l.getAccuracy() >= lastLocation.getAccuracy() && l.distanceTo(lastLocation) < l.getAccuracy() && !force) { Log.d(TAG, "Accuracy got worse and we are still " + "within the accuracy range.. Not updating"); return; } if (l.getTime() <= lastprovidertimestamp && !force) { Log.d(TAG, "Timestamp not never than last"); return; } } // upload/store your location here }

Cosas para considerar:

  • No solicite actualizaciones de GPS con demasiada frecuencia, consume energía de la batería. Actualmente uso 30 min por defecto para mi aplicación.

  • agregue una verificación de ''distancia mínima a la última ubicación conocida''. sin esto, sus puntos "saltarán" cuando el GPS no esté disponible y la ubicación se esté triangulando desde las torres celulares. o puede verificar si la nueva ubicación está fuera del valor de precisión de la última ubicación conocida.


hola, este es un enlace que podrá dar la totalidad del código fuente para integrar el de la ubicación de gps que podrá rastrear a cualquiera de las personas por gps y ti informará:

como: http://code.google.com/p/mytracks/


Respondiendo los dos primeros puntos :

  • El GPS siempre le dará una ubicación más precisa, si está habilitada y si no hay muros gruesos alrededor .

  • Si la ubicación no cambió, puede llamar a getLastKnownLocation(String) y recuperar la ubicación inmediatamente.

Usando un enfoque alternativo :

Puede intentar obtener la identificación de celda en uso o todas las celdas vecinas

TelephonyManager mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); GsmCellLocation loc = (GsmCellLocation) mTelephonyManager.getCellLocation(); Log.d ("CID", Integer.toString(loc.getCid())); Log.d ("LAC", Integer.toString(loc.getLac())); // or List<NeighboringCellInfo> list = mTelephonyManager.getNeighboringCellInfo (); for (NeighboringCellInfo cell : list) { Log.d ("CID", Integer.toString(cell.getCid())); Log.d ("LAC", Integer.toString(cell.getLac())); }

Puede consultar la ubicación de la celda a través de varias bases de datos abiertas (por ejemplo, http://www.location-api.com/ o http://opencellid.org/ )

La estrategia sería leer la lista de ID de torre al leer la ubicación. Luego, en la siguiente consulta (10 minutos en tu aplicación), léelos nuevamente. Si al menos algunas torres son iguales, entonces es seguro usar getLastKnownLocation(String) . Si no lo están, entonces espere a onLocationChanged() . Esto evita la necesidad de una base de datos de terceros para la ubicación. También puedes probar este enfoque .


Recientemente refactorizado para obtener la ubicación del código, aprender algunas buenas ideas y finalmente lograr una biblioteca y demo relativamente perfectos.

La respuesta de @Gryphius es buena

//request all valid provider(network/gps) private boolean requestAllProviderUpdates() { checkRuntimeEnvironment(); checkPermission(); if (isRequesting) { EasyLog.d("Request location update is busy"); return false; } long minTime = getCheckTimeInterval(); float minDistance = getCheckMinDistance(); if (mMapLocationListeners == null) { mMapLocationListeners = new HashMap<>(); } mValidProviders = getValidProviders(); if (mValidProviders == null || mValidProviders.isEmpty()) { throw new IllegalArgumentException("Not available provider."); } for (String provider : mValidProviders) { LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { if (location == null) { EasyLog.e("LocationListener callback location is null."); return; } printf(location); mLastProviderTimestamp = location.getTime(); if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) { finishResult(location); } else { doLocationResult(location); } removeProvider(location.getProvider()); if (isEmptyValidProviders()) { requestTimeoutMsgInit(); removeUpdates(); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } }; getLocationManager().requestLocationUpdates(provider, minTime, minDistance, locationListener); mMapLocationListeners.put(provider, locationListener); EasyLog.d("Location request %s provider update.", provider); } isRequesting = true; return true; } //remove request update public void removeUpdates() { checkRuntimeEnvironment(); LocationManager locationManager = getLocationManager(); if (mMapLocationListeners != null) { Set<String> keys = mMapLocationListeners.keySet(); for (String key : keys) { LocationListener locationListener = mMapLocationListeners.get(key); if (locationListener != null) { locationManager.removeUpdates(locationListener); EasyLog.d("Remove location update, provider is " + key); } } mMapLocationListeners.clear(); isRequesting = false; } } //Compared with the last successful position, to determine whether you need to filter private boolean isNeedFilter(Location location) { checkLocation(location); if (mLastLocation != null) { float distance = location.distanceTo(mLastLocation); if (distance < getCheckMinDistance()) { return true; } if (location.getAccuracy() >= mLastLocation.getAccuracy() && distance < location.getAccuracy()) { return true; } if (location.getTime() <= mLastProviderTimestamp) { return true; } } return false; } private void doLocationResult(Location location) { checkLocation(location); if (isNeedFilter(location)) { EasyLog.d("location need to filtered out, timestamp is " + location.getTime()); finishResult(mLastLocation); } else { finishResult(location); } } //Return to the finished position private void finishResult(Location location) { checkLocation(location); double latitude = location.getLatitude(); double longitude = location.getLongitude(); float accuracy = location.getAccuracy(); long time = location.getTime(); String provider = location.getProvider(); if (mLocationResultListeners != null && !mLocationResultListeners.isEmpty()) { String format = "Location result:<%f, %f> Accuracy:%f Time:%d Provider:%s"; EasyLog.i(String.format(format, latitude, longitude, accuracy, time, provider)); mLastLocation = location; synchronized (this) { Iterator<LocationResultListener> iterator = mLocationResultListeners.iterator(); while (iterator.hasNext()) { LocationResultListener listener = iterator.next(); if (listener != null) { listener.onResult(location); } iterator.remove(); } } } }

Implementación completa: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java

1. Gracias a las ideas de la solución @Gryphius, también comparto el código completo.

2.Cada solicitud para completar la ubicación, es mejor eliminar Actualizaciones, de lo contrario, la barra de estado del teléfono siempre mostrará el ícono de posicionamiento


Skyhook (http://www.skyhookwireless.com/) tiene un proveedor de ubicación que es mucho más rápido que el estándar que proporciona Google. Puede que sea lo que estás buscando. No estoy afiliado con ellos.