Хороший способ получить местоположение пользователя в Android

Проблема:

Получение текущего местоположения пользователя в пределах порогового значения ASAP и в то же время сохранение батареи.

Почему проблема является проблемой:

Во-первых, у android есть два провайдера; Сети и GPS. Иногда сеть лучше, а иногда GPS лучше.

Под «лучше» я подразумеваю соотношение скорости и точности.
Я готов пожертвовать точностью в несколько метров, если я смогу получить место почти мгновенно и без включения GPS.

Во-вторых, если вы запрашиваете обновления для изменений местоположения, то ничего не отправляется, если текущее местоположение является стабильным.

В Google есть пример определения «лучшего» местоположения здесь: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
Но я думаю, что это не так близко, как должно быть / могло быть.

Я немного смущен, почему у google нет нормализованного API для местоположения, разработчику не нужно заботиться о том, где находится местоположение, вы должны просто указать, что хотите, и телефон должен выбрать для вас.

Мне нужна помощь:

Мне нужно найти хороший способ определить «лучшее» место, может быть, хотя некоторые эвристические или, возможно, через какую-то стороннюю библиотеку.

Это не значит определить лучшего поставщика!
Я, вероятно, собираюсь использовать всех провайдеров и выбрать лучших из них.

Фон приложения:

Приложение будет собирать местоположение пользователя с фиксированным интервалом (скажем, каждые 10 минут или около того) и отправлять его на сервер.
Приложение должно сохранять как можно больше батареи, а местоположение должно иметь точность X (50-100?).

Цель состоит в том, чтобы позже смочь построить дорожку пользователя в течение дня на карте, поэтому мне нужна достаточная точность для этого.

Разное:

Как вы считаете, разумные значения при желаемой и приемлемой точности?
Я использую 100 м, как принято, и 30 м по желанию, это много, чтобы спросить?
Я хочу, чтобы позже можно было построить путь пользователя на карте.
100 м для желаемого и 500 м для приема лучше?

Кроме того, сейчас у меня есть GPS на максимум 60 секунд на обновление местоположения, слишком ли коротко, чтобы получить место, если вы находитесь в помещении с точностью до 200 м?


Это мой текущий код, любая обратная связь оценена (помимо отсутствия проверки ошибок, которая является 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); } 

Solutions Collecting From Web of "Хороший способ получить местоположение пользователя в Android"

Похоже, мы кодируем одно и то же приложение 😉
Вот моя текущая реализация. Я все еще на стадии бета-тестирования моего приложения для загрузки GPS, поэтому может быть много возможных улучшений. Но, похоже, он работает очень хорошо.

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

Изменить: вот часть, которая запрашивает периодические обновления от поставщиков местоположения:

 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 } 

Что нужно учитывать:

  • Не запрашивайте обновления GPS слишком часто, он истощает заряд батареи. В настоящее время я использую 30 минут для моего приложения.

  • Добавьте проверку «минимальное расстояние до последнего известного местоположения». Без этого ваши очки будут «прыгать», когда GPS недоступен, и местоположение будет триангулироваться от ячеек. Или вы можете проверить, находится ли новое местоположение вне значения точности из последнего известного местоположения.

Чтобы выбрать нужного провайдера для вашего приложения, вы можете использовать объекты 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); 

Прочтите документацию для requestLocationUpdates для получения более подробной информации о том, как учитываются аргументы:

Частоту уведомления можно контролировать с помощью параметров minTime и minDistance. Если minTime больше 0, LocationManager может потенциально отдохнуть за миллисекунды minTime между обновлениями местоположения для экономии энергии. Если minDistance больше 0, местоположение будет транслироваться только в том случае, если устройство перемещается с помощью счетчиков minDistance. Чтобы получать уведомления как можно чаще, установите оба параметра равными 0.

Другие мысли

  • Вы можете контролировать точность объектов местоположения с помощью Location.getAccuracy () , которая возвращает оценочную точность положения в метрах.
  • Criteria.ACCURACY_HIGH должен давать вам ошибки ниже 100 м, что не так хорошо, как GPS может быть, но соответствует вашим потребностям.
  • Вам также необходимо следить за статусом провайдера вашего местоположения и переключиться на другого провайдера, если он становится недоступным или отключенным пользователем.
  • Пассивный провайдер также может быть хорошим подспорьем для такого приложения: идея состоит в том, чтобы использовать обновления местоположения всякий раз, когда они запрашиваются другим приложением и транслируются по всей стране.

Отвечая на первые два пункта :

  • GPS всегда дает вам более точное местоположение, если оно включено, и если вокруг нет толстых стен .

  • Если местоположение не изменилось, вы можете вызвать getLastKnownLocation (String) и немедленно получить местоположение.

Использование альтернативного подхода :

Вы можете попробовать использовать идентификатор ячейки или все соседние ячейки

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

Вы можете обратиться к местоположению ячеек через несколько открытых баз данных (например, http://www.location-api.com/ или http://opencellid.org/ )


Стратегия будет состоять в том, чтобы прочитать список идентификаторов башни при чтении местоположения. Затем, в следующем запросе (10 минут в вашем приложении), прочитайте их снова. Если по крайней мере некоторые башни одинаковы, тогда безопасно использовать getLastKnownLocation(String) . Если это не так, то ждите onLocationChanged() . Это позволяет избежать необходимости использования базы данных сторонних разработчиков. Вы также можете попробовать этот подход .

Это мое решение, которое работает достаточно хорошо:

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

Точность местоположения зависит главным образом от используемого провайдера:

  1. GPS – получите точность в несколько метров (при условии, что у вас есть прием GPS)
  2. Wi-Fi – получите точность в несколько сотен метров
  3. Cell Network – Получит очень неточные результаты (я видел отклонение до 4 км …)

Если это то, что вы ищете, то GPS – это ваш единственный вариант.

Я читал здесь очень информативную статью об этом.

Что касается таймаута GPS – 60 секунд должно быть достаточно, и в большинстве случаев даже слишком много. Я думаю, что 30 секунд в порядке, а иногда даже меньше 5 секунд …

Если вам нужно только одно место, я бы предположил, что в вашем методе onLocationChanged , как только вы получите обновление, вы onLocationChanged регистрацию слушателя и избегаете ненужного использования GPS.

Android-ReactiveLocation – еще одна хорошая библиотека для управления местоположением на Android.

Небольшая библиотека, которая обертывает API сервисов Google Play в ярких RxJava Observables, уменьшает минимальный шаблон.

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

Hi это одна ссылка, которая сможет дать всему исходному коду объединить значение местоположения gps, которое сможет отслеживать любого из пользователей gps и ti, сообщая:

Например: http://code.google.com/p/mytracks/

В настоящее время я использую, так как это является надежным для получения местоположения и расчета расстояния для моего приложения …… Я использую это для моего приложения такси.

Используйте API-интерфейс fusion, который разработчик Google разработал с использованием GPS-датчика, магнитометра, акселерометра, также используя Wifi или ячейку для расчета или оценки местоположения. Он также может точно определять местоположение в здании. Для получения подробной информации перейдите по ссылке 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; } } } 

По моему опыту, я нашел, что лучше всего пойти с GPS-исправлением, если оно не доступно. Я не знаю много о других провайдерах местоположения, но я знаю, что для GPS есть несколько трюков, которые можно использовать, чтобы дать немного точности измерения гетто. Высота – это знак, поэтому вы можете проверить смешные ценности. В настройках местоположения Android есть точность. Также, если вы можете увидеть количество используемых спутников, это также может указывать на точность.

Интересным способом получить лучшее представление о точности можно было бы запросить набор исправлений очень быстро, например ~ 1 / сек в течение 10 секунд, а затем спать в течение минуты или двух. Один из разговоров, с которыми я столкнулся, привел к тому, что некоторые устройства Android все равно это сделают. Затем вы отсеивали выбросы (я слышал фильтр Калмана, упомянутый здесь) и использовал какую-то стратегию центрирования, чтобы получить одно исправление.

Очевидно, что глубина, которую вы получаете, зависит от того, насколько жесткими ваши требования. Если у вас есть особенно строгие требования, чтобы получить наилучшее местоположение, я думаю, вы обнаружите, что местоположение GPS и сеть аналогичны яблок и апельсинов. Также GPS может отличаться от устройства к устройству.

Skyhook (http://www.skyhookwireless.com/) имеет провайдера местоположения, который намного быстрее, чем стандартный, который предоставляет Google. Возможно, это то, что вы ищете. Я не связан с ними.