Android: LocationManager x Google Play Services

151

Desejo criar um aplicativo que gere a localização atual do usuário e encontre pontos de interesse (como bares, restaurantes etc.) próximos a ele por meio da API do Google Places .

Ao pesquisar na Web por um lugar para começar, me deparei com alguns tutoriais que usam a LocationManagerclasse e outros que usam o Google Play Services para encontrar a localização dos usuários.

À primeira vista, os dois fazem a mesma coisa, mas, como sou novo nisso, fiquei um pouco confuso e não sei qual método atende melhor às minhas necessidades. Então, eu quero lhe perguntar:

Quais são as diferenças entre esses dois métodos para encontrar locais (se houver algum)?

SoCo
fonte
1
visite aqui stackoverflow.com/questions/21397177/…
Mohammad Tauqir

Respostas:

319

Localização do usuário no Android

Obter a localização do usuário no Android é um pouco menos direto do que no iOS. Para começar a confusão, existem duas maneiras totalmente diferentes de fazer isso. O primeiro está usando APIs do Android android.location.LocationListenere o segundo está usando as APIs do Google Play Services com.google.android.gms.location.LocationListener. Vamos passar por ambos.

  1. API de localização do Android

    As APIs de localização do Android usam três provedores diferentes para obter a localização -

    • LocationManager.GPS_PROVIDER- Este provedor determina a localização usando satélites. Dependendo das condições, esse provedor pode demorar um pouco para retornar uma correção de local.
    • LocationManager.NETWORK_PROVIDER- Este provedor determina a localização com base na disponibilidade da torre de celular e pontos de acesso Wi-Fi. Os resultados são recuperados por meio de uma pesquisa de rede.
    • LocationManager.PASSIVE_PROVIDER- Este provedor retornará locais gerados por outros fornecedores. Você recebe atualizações de localização passivamente quando outros aplicativos ou serviços as solicitam sem realmente solicitar os locais.

A essência disso é que você obtém um objeto do LocationManagersistema, implementa LocationListenere chama requestLocationUpdateso LocationManager.

Aqui está um trecho de código:

    LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
    public void onLocationChanged(Location location) {
      // Called when a new location is found by the network location provider.
      makeUseOfNewLocation(location);
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {}

    public void onProviderEnabled(String provider) {}

    public void onProviderDisabled(String provider) {}
  };

// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

Guia da API do Google sobre estratégias de localizaçãoexplica o código muito bem. Mas eles também mencionam que, na maioria dos casos, você obtém melhor desempenho da bateria e precisão mais apropriada usando a API dos Serviços de Localização do Google . Agora a confusão começa!

  1. API de serviços de localização do Google

A API dos Serviços de Localização do Google faz parte do APK do Google Play Services (veja como configurá-lo ). Eles são construídos sobre a API do Android. Essas APIs fornecem um "provedor de localização fundida" em vez dos provedores mencionados acima. Esse provedor escolhe automaticamente o provedor subjacente a ser usado, com base na precisão, no uso da bateria etc. É rápido porque você obtém a localização de um serviço em todo o sistema que o atualiza constantemente. E você pode usar recursos mais avançados, como geofencing.

Para usar os Serviços de Localização do Google, seu aplicativo precisa se conectar ao GooglePlayServicesClient. Para se conectar ao cliente, sua atividade (ou fragmento, mais ou menos) precisa implementar GooglePlayServicesClient.ConnectionCallbackse fazer GooglePlayServicesClient.OnConnectionFailedListenerinterface. Aqui está um código de exemplo:

    public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {
    LocationClient locationClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        locationClient = new LocationClient(this, this, this);
    }

    @Override
    public void onConnected(Bundle bundle) {
    Location location = locationClient.getLastLocation() ;
        Toast.makeText(this, "Connected to Google Play Services", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDisconnected() {
    Toast.makeText(this, "Connected from Google Play Services.", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // code to handle failed connection
        // this code can be found here — http://developer.android.com/training/location/retrieve-current.html 
    }
  • Por que é locationClient.getLastLocation()nulo?

O locationClient.getLastLocation()obtém o último local conhecido do cliente. No entanto, o provedor de localização fundida somente manterá a localização em segundo plano se pelo menos um cliente estiver conectado a ela. Depois que o primeiro cliente se conectar, ele tentará imediatamente obter um local. Se sua atividade for o primeiro cliente a se conectar e você ligar getLastLocation()imediatamente onConnected(), isso poderá não ser suficiente para o primeiro local entrar. Isso resultará em locationser null.

Para resolver esse problema, é necessário aguardar (indeterminadamente) até que o provedor obtenha o local e depois ligar getLastLocation(), o que é impossível saber. Outra opção (melhor) é implementar a com.google.android.gms.location.LocationListenerinterface para receber atualizações periódicas de localização (e desativá-la assim que você receber a primeira atualização).

    public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
    // . . . . . . . . more stuff here 
    LocationRequest locationRequest;
    LocationClient locationClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // . . . . other initialization code
        locationClient = new LocationClient(this, this, this);
    locationRequest = new LocationRequest();
    // Use high accuracy
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        // Set the update interval to 5 seconds
    locationRequest.setInterval(UPDATE_INTERVAL);
        // Set the fastest update interval to 1 second
    locationRequest.setFastestInterval(FASTEST_INTERVAL);
    }
    // . . . . . . . . other methods 
    @Override
    public void onConnected(Bundle bundle) {
        Location location = locationClient.getLastLocation();
        if (location == null)
            locationClient.requestLocationUpdates(locationRequest, this);
        else
            Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
    }
    // . . . . . . . . other methods
    @Override
    public void onLocationChanged(Location location) {
        locationClient.removeLocationUpdates(this);
        // Use the location here!!!
    }

Nesse código, você está verificando se o cliente já tem o último local (em onConnected). Caso contrário, você está solicitando atualizações de local e desativando as solicitações (no onLocationChanged()retorno de chamada) assim que receber uma atualização.

Observe que ele locationClient.requestLocationUpdates(locationRequest, this);precisa estar dentro do onConnectedretorno de chamada, ou você receberá um IllegalStateExceptionporque estará tentando solicitar locais sem estar conectado ao cliente do Google Play Services.

  • O usuário desativou os Serviços de Localização

Muitas vezes, o usuário teria os serviços de localização desativados (para economizar bateria ou motivos de privacidade). Nesse caso, o código acima ainda solicitará atualizações de local, masonLocationChanged nunca será chamado. Você pode interromper as solicitações verificando se o usuário desativou os serviços de localização.

Se o seu aplicativo exigir que eles ativem os serviços de localização, você deseja mostrar uma mensagem ou um brinde. Infelizmente, não há como verificar se o usuário desativou os serviços de localização na API de serviços de localização do Google. Para isso, você precisará recorrer à API do Android.

No seu onCreatemétodo:

    LocationManager manager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
    locationEnabled = false;
    Toast.makeText(getActivity(), "Enable location services for accurate data", Toast.LENGTH_SHORT).show();
}
else locationEnabled = true;

E use a locationEnabledbandeira no seu onConnectedmétodo assim:

    if (location != null) {
    Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
    locationClient.requestLocationUpdates(locationRequest, this);
}

ATUALIZAR

O documento é atualizado, o LocationClient é removido e a API suporta o GPS com um clique na caixa de diálogo:

task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
    // All location settings are satisfied. The client can initialize
    // location requests here.
    // ...
}
});

task.addOnFailureListener(this, new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        if (e instanceof ResolvableApiException) {
            // Location settings are not satisfied, but this can be fixed
            // by showing the user a dialog.
            try {
                // Show the dialog by calling startResolutionForResult(),
                // and check the result in onActivityResult().
                ResolvableApiException resolvable = (ResolvableApiException) e;
                resolvable.startResolutionForResult(MainActivity.this,
                        REQUEST_CHECK_SETTINGS);
            } catch (IntentSender.SendIntentException sendEx) {
                // Ignore the error.
            }
        }
    }
});

Link https://developer.android.com/training/location/change-location-settings#prompt

Novo cliente de localização: FusedLocationProviderClient

  private FusedLocationProviderClient fusedLocationClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}

É recomendável acessar https://developer.android.com/training/location antes de executar qualquer tarefa de localização.

pRaNaY
fonte
9
Você pode usar SettingsApi.checkLocationSettings()para verificar se o usuário ativou os Serviços de Localização (consulte aqui: developers.google.com/android/reference/com/google/android/gms/… ).
kaolick
3
LocationClient não existe mais. Para um guia atualizado e claro para Localização, verifique este artigo: blog.teamtreehouse.com/beginners-guide-location-android
lm2a
1
E página de treino com o exemplo SettingsApi: developer.android.com/training/location/...
androidguy
2
Você também pode criar uma cerca geográfica usando LocationManager! A API da localização fundida funciona em dispositivos que não possuem serviços do Google Play?
Muhammad Babar
Esta pode ser uma outra melhor maneira de verificar GPS ativar / desativar o status fun isLocationEnabled(context: Context): Boolean { val locationMode: Int try { locationMode = Settings.Secure.getInt( context.contentResolver, Settings.Secure.LOCATION_MODE ) } catch (e: SettingNotFoundException) { e.printStackTrace() return false } return locationMode != Settings.Secure.LOCATION_MODE_OFF }
Wahib Ul Haq
32

Na minha experiência, "precisão mais apropriada" não significa melhor por nenhum meio. A menos que esteja faltando alguma coisa, se você quiser garantir que o GPS seja usado, o LocationManager é o único caminho a percorrer. Rastreamos veículos com nosso aplicativo e, novamente, a menos que esteja faltando alguma coisa, o Google Play Services fornece alguns locais muito imprecisos com bastante frequência.

Kit
fonte
2
Sim, pela minha experiência, o Google Play Services algumas vezes fornece um local impreciso.
VY
2
Sim, a API dos Serviços de Localização dos Serviços do Google Play pode fornecer informações de localização muito enganadoras. Os modems WiFi são movidos, os modems WiFi são atualizados com informações de localização incorretas (por exemplo, se a localização é falsificada por um dispositivo Android que atualiza a localização do modem WiFi) e existem várias outras circunstâncias que podem resultar em dados de localização incorretos da triangulação do modem WiFi. Em todos os nossos aplicativos em que a localização precisa é obrigatória, usamos apenas GPS.
user1608385
27

Você deve usar a API do local dos Serviços do Google Play em vez do LocationManager. De acordo com os documentos:

As APIs de localização dos serviços do Google Play são preferidas às APIs de localização da estrutura Android (android.location) como uma maneira de adicionar reconhecimento de localização ao seu aplicativo. Se atualmente você usa as APIs de localização da estrutura do Android, é altamente recomendável que você mude para as APIs de localização dos serviços do Google Play o mais rápido possível.

Quanto ao porquê de mudar, o Google diz o seguinte:

A API dos Serviços de Localização do Google, parte do Google Play Services, fornece uma estrutura de alto nível mais poderosa que lida automaticamente com provedores de localização, movimento do usuário e precisão da localização. Ele também lida com a programação de atualização de local com base nos parâmetros de consumo de energia que você fornece. Na maioria dos casos, você obtém melhor desempenho da bateria e precisão mais apropriada usando a API dos Serviços de Localização.

NoChinDeluxe
fonte
2
Você tem links para essa documentação de onde são essas citações? Seria interessante ver se o Google está dizendo algo diferente agora.
Edward Brey 26/11
3
É claro que eles dizem isso porque querem seus dados de localização!
Flyview 17/01/19
Quando você adiciona serviços do Google Play ao seu aplicativo, se um usuário o instalar, ele será solicitado a "atualizar" os serviços do Google Play para usar seu aplicativo. Caso o telefone esteja quase cheio (com memes e outras coisas do whatsapp) ou o usuário não tenha os dados, desculpe por você, meu amigo
Dr. Deo
2
@Flyview Yep! Lol, a maneira como eles falam faz parecer uma solução mágica! A maior desvantagem é que você precisa do Google Play Services no dispositivo !!!
varun
25

Estou usando a API dos Serviços de Localização do Google há um bom tempo. Ele tem vantagens, pois encapsula a complexidade de ter várias fontes para determinar posições. No entanto, encapsula muito fortemente , de modo que, quando você obtém uma posição estranha, não tem como determinar de onde veio essa posição estranha.

Na vida real, tive vários valores estranhos surgindo, a dez quilômetros da posição atual. A única explicação é que esses locais malucos decorrem de erros nos bancos de dados Googles Wi-Fi ou NWK - erros que sempre estarão lá, pois as topologias de Wi-Fi e de rede mudam todos os dias. Mas infelizmente (e surpreendentemente) a API não fornece informações sobre como uma posição individual foi derivada.

insira a descrição da imagem aqui

Isso deixa você com os problemas de filtrar os valores de aberração com base na verificação de plausibilidade de velocidade, aceleração, rolamento, etc.

... ou volte para a boa e antiga API de estrutura e use apenas GPS, que foi o que eu decidi fazer até o Google melhorar a API fundida.

j3App
fonte
7

A API dos Serviços de Localização do Google , parte do Google Play Services, fornece uma estrutura de alto nível mais poderosa que lida automaticamente com provedores de localização , movimento do usuário e precisão da localização . Ele também lida com a programação de atualização de local com base nos parâmetros de consumo de energia que você fornece. Na maioria dos casos, você obtém melhor desempenho da bateria e precisão mais apropriada usando a API dos Serviços de Localização.

Diferenças mais detalhadas entre as duas APIs de localização de serviço do Google Play da API e a API de localização do Android Framework podem ser encontradas aqui

Dhruvam Gupta
fonte
Usei sua resposta para responder minha própria pergunta, se estiver tudo bem. Muito obrigado! stackoverflow.com/questions/39852955/…
Leniaal 5/16
@Leniaal, então você não acha que minha resposta merece votos positivos?
Dhruvam Gupta
Esse é um documento antigo de três anos. Mas aqui está um sinal de mais 1
Drew
5

Sim, a API dos Serviços de Localização dos Serviços do Google Play pode fornecer informações de localização muito enganadoras. Os modems WiFi são movidos, os modems WiFi são atualizados com informações de localização incorretas (por exemplo, se a localização é falsificada por um dispositivo Android que atualiza a localização do modem WiFi) e existem várias outras circunstâncias que podem resultar em dados de localização incorretos da triangulação do modem WiFi. Em todos os nossos aplicativos em que a localização precisa é obrigatória, usamos apenas GPS.

user1608385
fonte
4

Diferenças entre a API de localização do serviço Google Play de duas APIs e a API de localização da estrutura do Android com base no serviço GPS

FusedLocationProviderClient

  1. Para a 1ª busca, o local não deve ser nulo (por exemplo: outro aplicativo precisa atualizar o local Lastknow no banco de dados GoogleplayService. Se for nulo, é necessário contornar o problema)
  2. Para a próxima busca seqüencial, ele usa o requestLocationUpdates()método para buscar a localização.
  3. A busca do local é baseada apenas locationRequest.setInterval(milliseconds)e setFastestInterval(milliseconds), não na alteração da localização do usuário
  4. O valor LatLng retornado contém apenas 7 valores decimais (por exemplo: 11.9557996, 79.8234599), não tão precisos
  5. Recomendado, quando o requisito do seu aplicativo leva a uma distância atual insignificante de (precisão de 50 a 100 metros)
  6. Eficaz no uso da bateria.

LocationManager Api

  1. A busca da localização do usuário é chamada usando locationManager.requestLocationUpdates ()
  2. A busca da localização com base na alteração da localização do usuário e nos intervalos de tempo locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, milliseconds, mindistance, Mylocationlistener)

  3. O valor LatLng retornado contém 14 valores decimais (por exemplo: 11.94574594963342 79.81166719458997) valores de localização precisos

  4. Recomendado para aplicativos baseados em localização, quando precisar de mais precisão, mesmo em metros.
  5. O uso da bateria é baseado no intervalo e na distância de busca.
Sackurise
fonte
Ei! 1 ° é no máximo 111_111 metros (20_000_000 / 180). Então, 0.0000001 ° é 0.011m = 1 cm. Não sei onde você precisa de uma melhor resolução GPS. E eu nem sei como conseguir uma melhor resolução de GPS.
21819 babay