Solicitar atualizações de localização

O uso adequado das informações de localização pode ser vantajoso para os usuários do seu app. Por exemplo, se o app ajudar o usuário a encontrar o caminho enquanto anda ou dirige ou se o app rastrear o local dos recursos, ele precisará determinar a localização do dispositivo em intervalos regulares. Além da localização geográfica (latitude e longitude), você pode oferecer mais informações ao usuário, como rumo (direção horizontal do trajeto), altitude ou velocidade do dispositivo. Essas e outras informações estão disponíveis no objeto Location que seu app pode recuperar do provedor de localização combinada. Em resposta, a API atualiza seu app periodicamente com a melhor localização disponível com base nos provedores de localização ativos no momento, por exemplo, Wi-Fi e Sistema de Posicionamento Global (GPS). A precisão do local é determinada pelos provedores, pelas permissões de localização solicitadas e pelas opções definidas na solicitação de localização.

Esta lição mostra como solicitar atualizações regulares da localização de um dispositivo usando o método requestLocationUpdates() no provedor de localização combinada.

Ver a última localização conhecida

O último local conhecido do dispositivo oferece uma base útil como ponto de partida, garantindo que o app tenha uma localização conhecida antes de iniciar as atualizações periódicas. Esta lição sobre como Ver a última localização conhecida mostra como ter acesso à última localização conhecida ao chamar getLastLocation(). Os snippets nas seções a seguir presumem que seu app já tenha recuperado e armazenado o último local conhecido como um objeto Location na variável global mCurrentLocation.

Fazer uma solicitação de local

Antes de solicitar atualizações de local, seu app precisa se conectar aos Serviços de localização e fazer uma solicitação de local. A lição sobre Como mudar as configurações de localização mostra como fazer isso. Quando a solicitação for realizada, você poderá iniciar atualizações regulares chamando requestLocationUpdates().

Dependendo da forma da solicitação, o provedor de localização combinada invoca o método de callback LocationCallback.onLocationResult() e transmite uma lista de objetos Location ou emite uma PendingIntent que contém o local nos dados estendidos. A precisão e a frequência das atualizações são afetadas pelas permissões de localização solicitadas e pelas opções definidas no objeto da solicitação.

Esta lição mostra como receber a atualização com a abordagem de callback LocationCallback. Chame requestLocationUpdates(), transmitindo a instância do objeto LocationRequest e um LocationCallback. Defina um método startLocationUpdates() conforme mostrado na amostra de código a seguir.

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

O snippet de código acima se refere a uma sinalização booleana, requestingLocationUpdates, usada para rastrear se o usuário ativou ou desativou as atualizações de localização. Se os usuários desativaram essas atualizações, você pode informá-los da solicitação de localização do app. Para saber mais sobre a retenção do valor da sinalização booleana em instâncias da atividade, consulte Salvar o estado da atividade.

Definir o callback de atualizações de localização

O provedor de localização combinada invoca o método de callback LocationCallback.onLocationResult(). O argumento de entrada contém um objeto Location de lista com a latitude e a longitude do local. O snippet a seguir mostra como implementar a interface LocationCallback, definir o método e, em seguida, ver a data e a hora da atualização de localização e exibir a latitude, a longitude e o carimbo de data/hora na interface de usuário do app:

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

Interromper atualizações de localização

Pense bem se quer ou não interromper as atualizações de localização quando a atividade não estiver mais em foco, como quando o usuário alternar para outro app ou para uma atividade diferente no mesmo app. Isso pode ser útil para reduzir o consumo de energia, desde que o app não precise coletar informações, mesmo quando estiver em execução em segundo plano. Esta seção mostra como interromper as atualizações no método onPause() da atividade.

Para interromper as atualizações de localização, chame removeLocationUpdates(), transmitindo um LocationCallback, como mostrado no exemplo de código a seguir:

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

Use um booleano, requestingLocationUpdates, para rastrear se as atualizações de localização estão ativadas no momento. No método onResume() da atividade, verifique se as atualizações de localização estão ativadas no momento. Caso contrário, ative-as:

Kotlin

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

Java

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

Salvar o estado da atividade

Mudanças na configuração do dispositivo, como uma mudança na orientação da tela ou no idioma, podem fazer com que a atividade atual seja destruída. Por isso, seu app precisa armazenar todas as informações necessárias para recriar a atividade. Uma forma de fazer isso é com um estado de instância armazenado em um objeto Bundle.

O exemplo de código a seguir mostra como usar o callback onSaveInstanceState() da atividade para salvar o estado da instância:

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

Defina um método updateValuesFromBundle() para restaurar os valores salvos a partir da instância anterior da atividade, se eles estiverem disponíveis. Chame o método onCreate() da atividade, conforme mostrado na amostra de código a seguir:

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

Para saber mais sobre como salvar um estado de instância, consulte a referência da classe Activity do Android.

Observação: para ter um armazenamento mais permanente, salve as preferências do usuário nas SharedPreferences do app. Defina a preferência compartilhada no método onPause() da atividade e recupere a preferência em onResume(). Para ver mais informações sobre como salvar preferências, leia Salvar conjuntos de chave-valor.

Outros recursos

Para saber mais, use os seguintes recursos:

Exemplos

  • App de exemplo para demonstrar o recebimento de atualizações do local no Android.