Хороший способ получить местоположение пользователя в 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?).

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

Разное:

Как вы считаете, разумные значения для желаемой и приемлемой точности?
Я использую 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()  TWO_MINUTES; boolean isSignificantlyOlder = 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  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); } 

Похоже, мы кодируем одно и то же приложение 😉
Вот моя текущая реализация. Я все еще на стадии бета-тестирования своего приложения для загрузки 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 с помощью 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 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/ )


Страtagsя будет состоять в том, чтобы прочитать список идентификаторов башни при чтении местоположения. Затем, в следующем запросе (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

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

используйте 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; } } } 

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

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

Я просмотрел интернет за обновленный (прошлый год) ответ, используя новейшие методы вытаскивания местоположения, предложенные google (для использования FusedLocationProviderClient). Я, наконец, приземлился на это:

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

Я создал новый проект и скопировал большую часть этого кода. Boom. Оно работает. И я думаю, что без устаревших строк.

Кроме того, симулятор, похоже, не получает местоположение GPS, о котором я знаю. Он дошел до сообщения об этом в журнале: «Все настройки местоположения выполнены».

И, наконец, на случай, если вы захотите узнать (я сделал), вам не нужен ключ google maps api с консоли разработчика Google, если все, что вам нужно, – это местоположение GPS.

Также полезно их учебное пособие. Но мне нужен полный пример с одним страницей / примером кода и т. Д. Их учебник складывается, но запутывает, когда вы новичок в этом, потому что вы не знаете, какие fragmentы вам нужны на более ранних страницах.

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

И, наконец, помните такие вещи:

Я не только должен был изменить mainActivity.Java. Мне также пришлось модифицировать Strings.xml, androidmanifest.xml и правильный build.gradle. А также ваш activity_Main.xml (но эта часть мне была легкой).

Мне нужно было добавить такие зависимости, как этот: реализация com.google.android.gms: play-services-location: 11.8.0, и обновить настройки моего SDK для Android, чтобы включить сервисы Google Play. (настройки параметров внешнего вида файла и инструменты SDK SDK SDK проверяют сервисы Google Play).

update: симулятор Android, похоже, получил события изменения местоположения и местоположения (когда я изменил значение в настройках сима). Но мои лучшие и первые результаты были на самом устройстве. Таким образом, это, вероятно, проще всего протестировать на реальных устройствах.

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

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

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

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

@ Ответ Грифиуса хорош

  //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 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 iterator = mLocationResultListeners.iterator(); while (iterator.hasNext()) { LocationResultListener listener = iterator.next(); if (listener != null) { listener.onResult(location); } iterator.remove(); } } } } 

Complete implementation: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java

1.Thanks @Gryphius solution ideas, I also share the complete code.

2.Each request to complete the location, it is best to removeUpdates, otherwise the phone status bar will always display the positioning icon

Skyhook (http://www.skyhookwireless.com/) has a location provider that is much faster than the standard one Google provides. It might be what you’re looking for. I’m not affiliated with them.

  • Android O - Старая служба переднего плана начала работать?
  • Слушатель Android Location в службе не работает, пока я не активирую WiFi / мобильную сеть
  • Разрешения на размещение в приложении android Marshmallow
  • RecyclerView - просмотр в определенном положении
  • Как получить текущее местоположение GPS программно в Android?
  • android getlastknownlocation возвращает null
  • Как работать с отложенным местоположением iOS 6?
  • LocationClient getLastLocation () return null
  • Android Google Maps API V2 Увеличить до текущего местоположения
  • Как измерить силу сигнала GPS на Android?
  • Каков самый простой и надежный способ получить текущее местоположение пользователя на Android?
  • Давайте будем гением компьютера.