Нюансы определения местоположения в android приложениях
Или почему location может возвращать null
Нюансы определения местоположения в android приложениях

Так вышло что в одном из моих приложений мне необходимо было знать примерное местоположение устройства. Так как вся суть была в определении восходов закатов и местоположения планет, то без локации приложение становилось бессмысленным, т.е. его нужно узнавать одноразово при запуске. Конечно можно добавлять возможность обновления местоположения, или ручного ввода координат, но это все дополнительные фичи, ключевая задача узнать местоположение устройства.
На текущий момент основная рекомендация от гугла использование Google Play Services и FusedLocationProviderClient как отправной точки. Оговорюсь сразу получение прав, проверка доступности сервисов и того что их версия больше 11.0 выходит за рамки данной статьи.
Итак казалось бы идеальный путь достаточно простой используем FusedLocationProviderClient и в соответствии с генеральной линией
в onCreate изображаем следующий код
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient
.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
// ...
}
}
});
Нюанс начинает именно здесь “Got last known location. In some rare situations this can be null.” К сожалению ситуации эти не так уж редки, хотя весьма специфичны.

Во первых в системных настройках андроида есть три варианта определения положения
- по всем источникам
- по координатам сети
- по спутникам GPS
И как ни странно у многих аппаратов по умолчанию выбран далеко не вариант по всем источникам, а только по gps.
В таких случаях если смартфон был перезагружен и первое приложение что запустилось ваше, то данный метод с 99% вероятностью вернет null даже если в самом устройстве данные есть еще с предыдущего определения gps. Из этого есть два выхода, и ниже будет пример использования обоих Во первых андроид позволяет программным способом запросить изменение системных настроек, чтоб пользователь изменил опцию на определение положение по всем источникам. Во вторых в случае если человек не согласился с этим, или же согласился, но опять получился null (если пользователь никогда не менял до этого настройки, то по WiFi сетям конечно сразу никаких зацепок и нет) то нужно получить один раз обновленные gps данных через
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
// Update UI with location data
// ...
}
};
};
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, null /* Looper */);
Таким образом вырисовывается следующая схема, если getLastLocation возвращает null, проверить настройку wifi после ответа пользователя, проверить еще раз getLastLocation если все равно null, запускаем обновление положения. Если сюда приплюсовать проверки разрешения, и версии google play services то это все раздувается несколько сильнее чем простое:
LocationServices.getFusedLocationProviderClient(this).getLastLocation()
Ниже представлены пример реализации на котлине и rxJava2 данных действий
LocationSettingDispatcher класс для работы с настройками андроида
[embed]
Тут необходимо пояснение, выше было сказано что хочется в настройках включить определение местоположения по всем источникам, а в запросе используется
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
Опытным путем было установлено что даже если включена опция определение только по спутникам gps, то все равно будет выводиться запрос на все источники, если же делать PRIORITY_LOW_POWER, то да по WiFi сетям проверка пройдет и в случае отсутствия разрешения оно будет запрошено, но GPS уже нет. Мне же нужно определение положения по всему что только возможно.
Так как запрос разрешения идет асинхронно то в activity нужно переопределить метод onActivityResult.
Но настройка местоположения это по сути побочный эффект, основной же класс работы с локацией представлен ниже
[embed]
в методе getLocation() с lastLocationMaybe мы может быть получим последнее известное положение и если оно пустое, то идет проверка на настройки аппарата, если все необходимые разрешения получены или уже были то мы пытаемся еще раз получить последнее положение и в случае его отсутствия остается последняя возможность запросить обновление местоположения. Возможные минусы текущей реализации в том что определение положения может занять много времени, а никакого таймаута тут не предусмотрено и запрос зашит в сам класс, но для примера это не критично и достаточно легко поправимо.
в Activity это все работает следующем образом
private lateinit var locationDeviceInteractor: LocationDeviceInteractor
private var disposable: Disposable? = null
...
// место где мы хотим получить местоположение устойства
locationDeviceInteractor = LocationDeviceInteractor(this)
disposable = locationDeviceInteractor
.getLocation()
.subscribe({
Log.e(it.latitude.toString(), it.longitude.toString())})
...
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
locationDeviceInteractor.onActivityResult(requestCode, resultCode)
}
override fun onDestroy() {
super.onDestroy()
disposable?.dispose()
...
} 메타데이터
- post_id
- 2a64cbf379b3
- slug
- нюансы-определения-местоположения-в-android-приложениях-2a64cbf379b3
- url
- https://medium.com/@vit.onix/%D0%BD%D1%8E%D0%B0%D0%BD%D1%81%D1%8B-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%BC%D0%B5%D1%81%D1%82%D0%BE%D0%BF%D0%BE%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2-android-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F%D1%85-2a64cbf379b3
- canonical_url
- https://medium.com/@vit.onix/%D0%BD%D1%8E%D0%B0%D0%BD%D1%81%D1%8B-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%BC%D0%B5%D1%81%D1%82%D0%BE%D0%BF%D0%BE%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2-android-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F%D1%85-2a64cbf379b3
- author_url
- https://medium.com/@vit.onix
- status
- ok
- fetched_at
- 2026-07-30 11:27:18