Запросить уведомления о местоположении

Правильное использование геоданных может быть полезно для пользователей вашего приложения. Например, если оно помогает пользователю найти дорогу во время ходьбы или вождения или если оно отслеживает местоположение объектов, ему необходимо регулярно получать данные о местоположении устройства. Помимо географического местоположения (широты и долготы), вы можете предоставить пользователю дополнительную информацию, например азимут (горизонтальное направление движения), высоту или скорость устройства. Эти и другие данные доступны в объекте Location, который ваше приложение может получить от поставщика геоданных из нескольких источников. В ответ API периодически обновляет в приложении данные о местоположении, используя наиболее точные сведения, полученные от доступных поставщиков геоданных, например Wi-Fi и GPS. Точность местоположения определяется поставщиками, разрешениями на доступ к местоположению, которые вы запросили, и параметрами, заданными в запросе местоположения.

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

Получение сведений о последнем известном местоположении

Последнее известное местоположение устройства – это удобная отправная точка, которая позволяет приложению получить данные о местоположении до начала периодических уведомлений о местоположении. В уроке Получение последнего известного местоположения рассказывается, как получить последнее известное местоположение, вызвав getLastLocation(). Фрагменты кода в следующих разделах предполагают, что ваше приложение уже получило последнее известное местоположение и сохранило его как объект Location в глобальной переменной mCurrentLocation.

Как запросить местоположение

Прежде чем запрашивать обновления местоположения, ваше приложение должно подключиться к сервисам геолокации и отправить запрос на получение местоположения. Подробнее о том, как это сделать, рассказывается в уроке Как изменить настройки геолокации. После того как запрос местоположения будет настроен, вы можете начать регулярные обновления, вызвав requestLocationUpdates().

В зависимости от формы запроса поставщик геоданных из нескольких источников либо вызывает метод обратного вызова LocationCallback.onLocationResult() и передает ему список объектов Location, либо выдает объект PendingIntent, который содержит местоположение в расширенных данных. Точность и частота обновлений зависят от разрешений на доступ к данным о местоположении, которые вы запросили, и параметров, заданных в объекте запроса местоположения.

В этом уроке рассказывается, как получить обновление с помощью обратного вызова LocationCallback. Вызовите метод requestLocationUpdates(), передав ему экземпляр объекта LocationRequest и LocationCallback. Определите метод startLocationUpdates(), как показано в примере кода ниже.

Kotlin

override fun onResume() {
    super.onResume()
    if (requestingLocationUpdates) startLocationUpdates()
}

private fun startLocationUpdates() {
    fusedLocationClient.requestLocationUpdates(locationRequest,
            locationCallback,
            Looper.getMainLooper())
}

Java

@Override
protected void onResume() {
    super.onResume();
    if (requestingLocationUpdates) {
        startLocationUpdates();
    }
}

private void startLocationUpdates() {
    fusedLocationClient.requestLocationUpdates(locationRequest,
            locationCallback,
            Looper.getMainLooper());
}

Обратите внимание, что в приведенном выше фрагменте кода используется логический флаг requestingLocationUpdates, который позволяет отслеживать, включил ли пользователь обновление геоданных. Если нет, вы можете сообщить ему о том, что приложению требуется доступ к местоположению. Подробнее о том, как сохранить значение логического флага в разных экземплярах операции, рассказывается в разделе Сохранение состояния операции.

Определите обратный вызов для обновления местоположения

Поставщик геоданных из нескольких источников вызывает метод обратного вызова LocationCallback.onLocationResult(). Входящий аргумент содержит объект списка Location, в котором указаны широта и долгота местоположения. В следующем фрагменте кода показано, как реализовать интерфейс LocationCallback и определить метод, а затем получить временную метку обновления местоположения и показать широту, долготу и временную метку в пользовательском интерфейсе приложения:

Kotlin

private lateinit var locationCallback: LocationCallback

// ...

override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
            locationResult ?: return
            for (location in locationResult.locations){
                // Update UI with location data
                // ...
            }
        }
    }
}

Java

private LocationCallback locationCallback;

// ...

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...

    locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult == null) {
                return;
            }
            for (Location location : locationResult.getLocations()) {
                // Update UI with location data
                // ...
            }
        }
    };
}

Отключить уведомления о местоположении

Подумайте, нужно ли прекращать обновление местоположения, когда пользователь переключается на другое приложение или на другое действие в том же приложении. Это может быть полезно для снижения энергопотребления, если приложению не нужно собирать информацию, даже когда оно работает в фоновом режиме. В этом разделе показано, как можно остановить обновления в методе onPause().

Чтобы остановить обновление местоположения, вызовите метод removeLocationUpdates(), передав ему объект LocationCallback, как показано в следующем примере кода:

Kotlin

override fun onPause() {
    super.onPause()
    stopLocationUpdates()
}

private fun stopLocationUpdates() {
    fusedLocationClient.removeLocationUpdates(locationCallback)
}

Java

@Override
protected void onPause() {
    super.onPause();
    stopLocationUpdates();
}

private void stopLocationUpdates() {
    fusedLocationClient.removeLocationUpdates(locationCallback);
}

Используйте логическое значение requestingLocationUpdates, чтобы отслеживать, включены ли сейчас обновления местоположения. В методе onResume() проверьте, включены ли уведомления о местоположении. Если нет, включите их.

Kotlin

override fun onResume() {
    super.onResume()
    if (requestingLocationUpdates) startLocationUpdates()
}

Java

@Override
protected void onResume() {
    super.onResume();
    if (requestingLocationUpdates) {
        startLocationUpdates();
    }
}

Сохранение состояния действия

Изменение конфигурации устройства, например ориентации экрана или языка, может привести к уничтожению текущего действия. Поэтому приложение должно хранить всю информацию, необходимую для воссоздания действия. Один из способов сделать это – использовать состояние экземпляра, хранящееся в объекте Bundle.

В приведенном ниже примере кода показано, как использовать обратный вызов onSaveInstanceState() для сохранения состояния экземпляра.

Kotlin

override fun onSaveInstanceState(outState: Bundle?) {
    outState?.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates)
    super.onSaveInstanceState(outState)
}

Java

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY,
            requestingLocationUpdates);
    // ...
    super.onSaveInstanceState(outState);
}

Определите метод updateValuesFromBundle(), чтобы восстановить сохраненные значения из предыдущего экземпляра операции, если они доступны. Вызовите метод из метода onCreate() объекта activity, как показано в следующем примере кода:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    updateValuesFromBundle(savedInstanceState)
}

private fun updateValuesFromBundle(savedInstanceState: Bundle?) {
    savedInstanceState ?: return

    // Update the value of requestingLocationUpdates from the Bundle.
    if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
        requestingLocationUpdates = savedInstanceState.getBoolean(
                REQUESTING_LOCATION_UPDATES_KEY)
    }

    // ...

    // Update UI to match restored state
    updateUI()
}

Java

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    updateValuesFromBundle(savedInstanceState);
}

private void updateValuesFromBundle(Bundle savedInstanceState) {
    if (savedInstanceState == null) {
        return;
    }

    // Update the value of requestingLocationUpdates from the Bundle.
    if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
        requestingLocationUpdates = savedInstanceState.getBoolean(
                REQUESTING_LOCATION_UPDATES_KEY);
    }

    // ...

    // Update UI to match restored state
    updateUI();
}

Подробнее о сохранении состояния экземпляра рассказывается в справочной статье о классе Android Activity.

Примечание. Чтобы настройки пользователя хранились дольше, вы можете сохранять их в SharedPreferences постоянном хранилище приложения. Задайте общую настройку в методе onPause() своей операции и получите ее в методе onResume(). Подробнее о том, как сохранять наборы пар "ключ-значение"…

Дополнительные ресурсы

Дополнительную информацию можно найти в следующих ресурсах:

Образцы