Эта проблема:
Получение текущего местоположения пользователя в пределах порога как можно скорее и в то же время экономить заряд батареи.
Почему проблема является проблемой:
Во-первых, у Android есть два провайдера; сеть и GPS. Иногда сеть лучше, а иногда лучше GPS.
Под «лучшим» я подразумеваю соотношение скорости и точности.
Я готов пожертвовать точностью в несколько метров, если смогу определить местоположение практически мгновенно и без включения GPS.
Во-вторых, если вы запрашиваете обновления для изменений местоположения, ничего не отправляется, если текущее местоположение стабильно.
У Google есть пример определения «лучшего» местоположения здесь: http://developer.android.com/guide/topics/location/obtainment-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);
}
источник
Ответы:
Похоже, мы кодируем одно и то же приложение ;-)
Вот моя текущая реализация. Я все еще на стадии бета-тестирования моего приложения для загрузки GPS, поэтому возможны многие улучшения. но, похоже, пока работает довольно хорошо.
Изменить: вот часть, которая запрашивает периодические обновления от поставщиков местоположения:
Что нужно учитывать:
не запрашивайте обновления GPS слишком часто, это разряжает батарею. В настоящее время я использую 30 минут по умолчанию для своего приложения.
добавить проверку «минимальное расстояние до последнего известного местоположения». без этого ваши точки будут «прыгать», когда GPS недоступен, а местоположение триангулируется от вышек сотовой связи. или вы можете проверить, находится ли новое местоположение за пределами значения точности из последнего известного местоположения.
источник
Чтобы выбрать подходящего поставщика местоположения для вашего приложения, вы можете использовать объекты Criteria :
Прочитайте документацию для requestLocationUpdates для более подробной информации о том, как аргументы принимаются во внимание:
Больше мыслей
Criteria.ACCURACY_HIGH
критерий должен дать вам ошибку ниже 100 м, что не так хорошо , как GPS может быть, но соответствуют вашим потребностям.источник
Criteria
но что, если последнее местоположение в сети является отличным (оно может узнать через Wi-Fi), и для его получения не требуется время или батарея (getLastKnown), тогда критерии, вероятно, будут игнорировать это и возвращать вместо этого GPS. Я не могу поверить, что Google сделал это трудным для разработчиков.Отвечая на первые два пункта :
GPS всегда даст вам более точное местоположение, если оно включено и если вокруг нет толстых стен .
Если местоположение не изменилось, вы можете вызвать getLastKnownLocation (String) и немедленно получить местоположение.
Используя альтернативный подход :
Вы можете попробовать использовать идентификатор ячейки или все соседние ячейки
Затем вы можете ссылаться на местоположение ячейки через несколько открытых баз данных (например, http://www.location-api.com/ или http://opencellid.org/ ).
Стратегия будет заключаться в чтении списка идентификаторов башен при чтении местоположения. Затем, в следующем запросе (10 минут в вашем приложении), прочитайте их снова. Если хотя бы несколько башен одинаковы, то их можно использовать безопасно
getLastKnownLocation(String)
. Если нет, тогда ждитеonLocationChanged()
. Это исключает необходимость использования сторонней базы данных для этого местоположения. Вы также можете попробовать этот подход .источник
Это мое решение, которое работает довольно хорошо:
источник
Точность определения местоположения зависит в основном от используемого поставщика местоположения:
Если вы ищете точность, то GPS - ваш единственный выбор.
Я прочитал очень информативную статью об этом здесь .
Что касается времени ожидания GPS - 60 секунд должно быть достаточно, а в большинстве случаев даже слишком много. Я думаю, что 30 секунд это нормально, а иногда даже меньше, чем 5 секунд ...
если вам нужно только одно местоположение, я рекомендую, чтобы в вашем
onLocationChanged
методе после получения обновления вы отменяли регистрацию слушателя и избегали ненужного использования GPS.источник
В настоящее время я использую это, поскольку это надежно для получения местоположения и расчета расстояния для моего приложения ...... я использую это для моего приложения такси.
используйте API-интерфейс fusion, разработанный Google-разработчиком с использованием GPS-датчика, магнитометра, акселерометра, а также Wi-Fi или местоположения ячейки для расчета или оценки местоположения. Он также может точно определять местоположение и внутри здания. для получения подробной информации перейдите по ссылке https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi
источник
Я искал в Интернете обновленный (в прошлом году) ответ, используя последние методы определения местоположения, предложенные Google (для использования FusedLocationProviderClient). Я наконец-то приземлился на это:
https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates
Я создал новый проект и скопировал большую часть этого кода. Boom. Оно работает. И я думаю без каких-либо устаревших строк.
Кроме того, симулятор, кажется, не получает местоположение GPS, о котором я знаю. Это действительно так далеко, как сообщать об этом в журнале: «Все настройки местоположения удовлетворены».
И, наконец, если вы хотите знать (я это сделал), вам НЕ нужен ключ API Google Maps из консоли разработчика Google, если вам нужно только местоположение GPS.
Также полезным является их учебник. Но я хотел полный одностраничный учебник / пример кода, и это. Их учебник сложен, но сбивает с толку, когда вы новичок в этом, потому что вы не знаете, какие части вам нужны из предыдущих страниц.
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 Studio, чтобы включить сервисы Google Play. (настройки файлов внешнего вида, системные настройки Android SDK SDK Tools, проверьте сервисы Google Play).
обновление: симулятор андроида, похоже, получал события локации и смены локации (когда я менял значение в настройках сима). Но мои лучшие и первые результаты были на реальном устройстве. Так что, вероятно, проще всего протестировать на реальных устройствах.
источник
Недавно проведен рефакторинг для получения местоположения кода, изучения некоторых хороших идей и, наконец, достижения относительно совершенной библиотеки и демоверсии.
@ Ответ Грифия хорош
Полная реализация: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java
1.Спасибо идеи решения @Gryphius, я также делюсь полным кодом.
2.Каждый запрос на заполнение местоположения лучше удалить с помощью обновлений, в противном случае в строке состояния телефона всегда будет отображаться значок позиционирования.
источник
По своему опыту, я нашел, что лучше всего использовать исправление GPS, если оно недоступно. Я не знаю много о других провайдерах определения местоположения, но я знаю, что для GPS есть несколько уловок, которые можно использовать, чтобы дать немного гетто точности измерения. Высота над уровнем моря часто является признаком, поэтому вы можете проверить смешные значения. На исправлениях местоположения Android есть мера точности. Также, если вы видите количество используемых спутников, это также может указывать на точность.
Интересный способ получить лучшее представление о точности может заключаться в том, чтобы очень быстро запросить набор исправлений, например, ~ 1 / сек в течение 10 секунд, а затем поспать минуту или две. Один разговор, на котором я был, привел к убеждению, что некоторые Android-устройства будут делать это в любом случае. Затем вы должны отсеять выбросы (я слышал, что фильтр Калмана упоминался здесь) и использовать какую-то стратегию центрирования, чтобы получить одно исправление.
Очевидно, глубина, к которой вы попадаете, зависит от того, насколько сложны ваши требования. Если вы предъявляете особенно строгие требования к получению ЛУЧШЕГО местоположения, я думаю, вы обнаружите, что GPS и сетевое местоположение такие же, как яблоки и апельсины. Также GPS может сильно отличаться от устройства к устройству.
источник
У Skyhook (http://www.skyhookwireless.com/) есть провайдер местоположения, который намного быстрее, чем стандартный, предоставляемый Google. Это может быть то, что вы ищете. Я не связан с ними.
источник