Przewodnik programisty Androida po interfejsie API usług lokalizacyjnych Google

Opublikowany: 2022-03-11

Znajomość lokalizacji użytkownika jest użyteczną informacją w wielu aplikacjach, które obecnie opracowujemy i wykorzystujemy. Istnieje wiele popularnych aplikacji lokalizacyjnych, które ułatwiają nam życie, a także zmieniają sposób, w jaki korzystamy z tych usług. Przykładem jest szalenie popularna aplikacja Foursquare, w której użytkownicy, którzy często odwiedzają placówki i „zameldują się”, często wygrywają zniżki. Uber, który umożliwia przejazd z telefonu komórkowego po niższej cenie niż zwykła taksówka. Lista jest duża i wciąż rośnie.

API usług lokalizacyjnych

W tym artykule zamierzamy zbudować prostą aplikację na Androida do określania szerokości i długości geograficznej użytkownika przy użyciu interfejsu API usług lokalizacyjnych Google dla systemu Android. Podczas tworzenia aplikacji na Androida istnieje kilka sposobów na uzyskanie lokalizacji użytkownika.

Pakiet „android.lokalizacja”

Pakiet „android.location” jest dostępny od pierwszego wprowadzenia Androida i daje nam dostęp do usług lokalizacyjnych. Usługi te umożliwiają aplikacjom otrzymywanie okresowych aktualizacji lokalizacji geograficznej urządzenia.

Pakiet zapewnia dwa sposoby pozyskiwania danych lokalizacyjnych:

  • LocationManager.GPS_PROVIDER: Określa lokalizację za pomocą satelitów. W zależności od warunków ten dostawca może trochę potrwać, zanim zwróci poprawkę lokalizacji.

  • LocationManager.NETWORK_PROVIDER: Określa lokalizację na podstawie dostępności pobliskich wież komórkowych i punktów dostępu Wi-Fi. To jest szybsze niż GPS_PROVIDER.

Kiedy szukasz lokalizacji użytkownika, musisz grać z tymi dostawcami i ich dostępnością. Najlepiej byłoby uzyskać pierwszą lokalizację za pomocą NETWORK_PROVIDER, która może nie jest tak dokładna, ale jest znacznie szybsza. Możesz wtedy spróbować zwiększyć dokładność, nasłuchując lepszego ustalenia lokalizacji za pomocą GPS_PROVIDER.

Interfejsy API dostarczane przez ten pakiet są dość niskopoziomowe i wymagają od dewelopera aplikacji obsługi drobniejszych szczegółów dotyczących określania, kiedy żądać danych lokalizacji i planować wywołania interfejsu API w zoptymalizowany sposób. Aby poprawić wrażenia programistów z usługami systemowymi opartymi na lokalizacji i ułatwić proces tworzenia aplikacji rozpoznających lokalizację, firma Google wprowadziła nowy sposób żądania lokalizacji użytkownika za pomocą Usług Google Play. Oferuje prostszy interfejs API z wyższą dokładnością, geofencing o małej mocy i wiele więcej.

Interfejs API usług lokalizacyjnych Google

Interfejs API usług lokalizacyjnych Google, znany również jako FusedLocationProviderApi, to zalecany przez Google sposób uzyskiwania lokalizacji użytkownika. Zapewnia najlepszą dokładność w oparciu o nasze potrzeby. Niektóre z zalet korzystania z tego interfejsu API w porównaniu z poprzednim to:

  • Prostota: w przeciwieństwie do poprzedniego interfejsu API, nie musisz już mieć do czynienia z wieloma dostawcami. Zamiast tego określasz potrzeby na wysokim poziomie, takie jak „wysoka dokładność” lub „niska moc”, i przyjmie odpowiednie podejście.

  • Dostępność: zapewnia aplikacji natychmiastowy dostęp do najlepszej, ostatniej znanej lokalizacji. Zwykle te informacje są łatwo dostępne, wystarczy o nie poprosić.

  • Efektywność energetyczna: Minimalizuje zużycie energii przez aplikację.

  • Wszechstronność: Spełnia szeroki zakres potrzeb, od zastosowań na pierwszym planie — wymagających bardzo dokładnych danych o lokalizacji, po zastosowania w tle — wymagające jedynie okresowych aktualizacji lokalizacji przy znikomym wpływie na moc.

Zbudujmy aplikację na Androida opartą na lokalizacji, korzystając z tego interfejsu API. W tym celu użyjemy sugerowanego przez Google IDE do tworzenia aplikacji na Androida - Android Studio. Rozpoczęcie pracy z Android Studio jest dość proste. Na ich stronie internetowej szczegółowo opisano procedurę instalacji i konfiguracji Android Studio, w tym sposób ładowania pierwszej aplikacji na Androida do rozwoju.

Android Studio powinno bardzo ułatwić nam pracę. Jednak musimy zacząć od skonfigurowania skryptu kompilacji i dodania Usług Google Play jako zależności dla tej aplikacji. Można to zrobić, modyfikując plik „build.gradle” w następujący sposób:

 dependencies { compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.google.android.gms:play-services:6.5.87' // Add this line }

W chwili pisania tego artykułu najnowsza dostępna wersja Usług Google Play to 6.5.87. Upewnij się, że zawsze sprawdzasz najnowszą dostępną wersję przed rozpoczęciem. Jeśli nowsze wersje pojawią się później i zdecydujesz się zaktualizować je do własnych projektów, przetestuj wszystkie funkcje związane z lokalizacją we wszystkich obsługiwanych wersjach Androida.

W tym momencie powinniśmy być w stanie rozpocząć właściwą pracę dla naszej aplikacji.

Prośba o pozwolenie, konfiguracja AndroidManifest.xml

Androidy mają określone funkcje bezpieczeństwa, które uniemożliwiają dowolnej aplikacji żądanie dokładnej lokalizacji użytkownika. Aby rozwiązać ten problem, musimy edytować plik „AndroidManifest.xml” i dodać uprawnienia, których potrzebujemy dla tej aplikacji:

 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Skoro już przy tym jesteśmy, powinniśmy również zdefiniować wersję Usług Google Play, z której korzystamy dla tej aplikacji:

 <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

Sprawdzanie dostępności usług Google Play

Przed uzyskaniem dostępu do funkcji udostępnianych przez Usługi Google Play musimy sprawdzić, czy na urządzeniu są zainstalowane Usługi Google Play oraz czy jest to ta, z której zamierzamy korzystać (6.5.87).

 private boolean checkGooglePlayServices(){ int checkGooglePlayServices = GooglePlayServicesUtil .isGooglePlayServicesAvailable(mContext); if (checkGooglePlayServices != ConnectionResult.SUCCESS) { /* * Google Play Services is missing or update is required * return code could be * SUCCESS, * SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, * SERVICE_DISABLED, SERVICE_INVALID. */ GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, mContext, REQUEST_CODE_RECOVER_PLAY_SERVICES).show(); return false; } return true; }

Ta metoda sprawdzi usługi Google Play, a jeśli urządzenie nie ma ich zainstalowanej (rzadko, ale widziałem takie przypadki), otworzy okno dialogowe z odpowiednim błędem i zaprosi użytkownika do zainstalowania/aktualizacji Usługi Google Play ze Sklepu Google Play.

Usługi Google Play

Po zakończeniu przez użytkownika rozwiązania dostarczonego przez „GooglePlayServicesUtil.getErrorDialog()”, wywoływana jest metoda wywołania zwrotnego „onActivityResult()”, więc musimy zaimplementować pewną logikę, aby obsłużyć to wywołanie:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_RECOVER_PLAY_SERVICES) { if (resultCode == RESULT_OK) { // Make sure the app is not already connected or attempting to connect if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); } } else if (resultCode == RESULT_CANCELED) { Toast.makeText(mContext, "Google Play Services must be installed.", Toast.LENGTH_SHORT).show(); finish(); } } }

Uzyskiwanie dostępu do interfejsów API Google

Aby uzyskać dostęp do interfejsów Google API, wystarczy wykonać jeszcze jeden krok: utworzyć instancję GoogleApiClient. Klient interfejsu API Google zapewnia wspólny punkt wejścia do wszystkich usług Google Play i zarządza połączeniem sieciowym między urządzeniem użytkownika a każdą usługą Google. Naszym pierwszym krokiem jest zainicjowanie połączenia. Zwykle nazywam ten kod z metody „onCreate” działania:

 protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); }

Łącząc serię wywołań metod, określamy implementację interfejsu wywołań zwrotnych i API usługi lokalizacji, których chcemy użyć. Implementacja interfejsu, w tym przypadku „this”, otrzyma odpowiedź na asynchroniczną metodę „connect()”, gdy połączenie z Usługami Google Play powiedzie się, zakończy się niepowodzeniem lub zostanie zawieszone. Po dodaniu tego kodu nasza „MainActivity” powinna wyglądać tak:

 package com.bitwoo.userlocation; import android.content.Intent; import android.location.Location; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.LocationServices; public class MainActivity extends ActionBarActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static int REQUEST_CODE_RECOVER_PLAY_SERVICES = 200; private GoogleApiClient mGoogleApiClient; private Location mLastLocation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (checkGooglePlayServices()) { buildGoogleApiClient(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private boolean checkGooglePlayServices() { int checkGooglePlayServices = GooglePlayServicesUtil .isGooglePlayServicesAvailable(this); if (checkGooglePlayServices != ConnectionResult.SUCCESS) { /* * google play services is missing or update is required * return code could be * SUCCESS, * SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, * SERVICE_DISABLED, SERVICE_INVALID. */ GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, this, REQUEST_CODE_RECOVER_PLAY_SERVICES).show(); return false; } return true; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_RECOVER_PLAY_SERVICES) { if (resultCode == RESULT_OK) { // Make sure the app is not already connected or attempting to connect if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); } } else if (resultCode == RESULT_CANCELED) { Toast.makeText(this, "Google Play Services must be installed.", Toast.LENGTH_SHORT).show(); finish(); } } } protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } @Override public void onConnected(Bundle bundle) { } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { } }

Następnie w naszej metodzie „onStart” wywołujemy metodę „connect” i czekamy na wywołanie metody zwrotnej „onConnected”:

 @Override protected void onStart() { super.onStart(); if (mGoogleApiClient != null) { mGoogleApiClient.connect(); } }

Metoda „onConnected” będzie wyglądać tak:

 @Override public void onConnected(Bundle bundle) { mLastLocation = LocationServices.FusedLocationApi.getLastLocation( mGoogleApiClient); if (mLastLocation != null) { Toast.makeText(this, "Latitude:" + mLastLocation.getLatitude()+", Longitude:"+mLastLocation.getLongitude(),Toast.LENGTH_LONG).show(); } }

To wywołanie zwrotne jest uruchamiane, gdy połączone są usługi Google Play, co oznacza, że ​​do tego czasu powinniśmy mieć ostatnią znaną lokalizację. Jednak ta lokalizacja może być pusta (jest to rzadkie, ale nie niemożliwe). W takim przypadku polecam słuchać aktualizacji lokalizacji, które zostaną omówione w dalszej części.

Nasłuchiwanie aktualizacji lokalizacji

Po wywołaniu „getLastLocation” możesz zażądać okresowych aktualizacji od dostawcy lokalizacji Fused. W zależności od aplikacji okres ten może być krótki lub długi. Na przykład, jeśli tworzysz aplikację, która śledzi lokalizację użytkownika podczas jazdy, będziesz musiał słuchać aktualizacji w krótkich odstępach czasu. Z drugiej strony, jeśli Twoja aplikacja ma udostępniać lokalizację użytkownika jego przyjacielowi, być może będziesz musiał raz na jakiś czas poprosić o lokalizację.

Tworzenie żądania jest dość proste - możesz wywołać tę metodę wewnątrz metody „onCreate”:

 protected void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(20000); mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); }

Tworzymy instancję nowego obiektu LocationRequest. Ustaw interwał na 20 sekund (20000 milisekund). Ponadto ustawiliśmy dławioną częstotliwość aktualizacji na 5 sekund. To mówi interfejsowi API, aby udostępniał aktualizacje co 20 sekund (najlepiej), ale jeśli w ciągu 5 sekund pojawi się zmiana, powinien to również zapewnić. Na koniec ustawiliśmy priorytet na „PRIORITY_HIGH_ACCURACY”, wśród innych dostępnych opcji priorytetów: PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER, PRIORITY_NO_POWER.

Po zbudowaniu żądania możesz rozpocząć nasłuchiwanie aktualizacji lokalizacji po uruchomieniu metody „onConnected()”:

 protected void startLocationUpdates() { LocationServices.FusedLocationApi.requestLocationUpdates( mGoogleApiClient, mLocationRequest, this); }

Teraz pozostaje tylko zaimplementować metodę wywołania zwrotnego, aby zadowolić interfejs LocationListener:

 public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { // ... @Override public void onLocationChanged(Location location) { mLastLocation = location; Toast.makeText(this, "Latitude:" + mLastLocation.getLatitude()+", Longitude:"+mLastLocation.getLongitude(),Toast.LENGTH_LONG).show(); } } 

przestań słuchać aktualizacji

Przestań słuchać aktualizacji

Ważne jest, aby wyraźnie przestać nasłuchiwać aktualizacji, gdy już ich nie potrzebujesz lub jeśli użytkownik opuści aplikację. Poniższa metoda powinna zostać wywołana z funkcji zwrotnej „onPause”:

 protected void stopLocationUpdates() { if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates( mGoogleApiClient, this); } }

… i odłączanie Google API:

 @Override protected void onStop() { super.onStop(); if (mGoogleApiClient != null) { mGoogleApiClient.disconnect(); } }

Zawijanie

Jak widać, podstawowe idee stojące za implementacją aplikacji obsługujących lokalizację w systemie Android są bardzo proste. Co więcej, dzięki dostępnym interfejsom API, które są zarówno proste w użyciu, jak i łatwe do zrozumienia, tworzenie podstawowych aplikacji opartych na lokalizacji na Androida nie powinno stanowić problemu. Mała przykładowa aplikacja, którą tutaj zbudowaliśmy, ma dokładnie to zademonstrować. Pełny kod źródłowy można znaleźć na GitHub. Należy pamiętać, że dla uproszczenia aplikacja nie obsługuje metody wywołania zwrotnego „onConnectionFailed”.

Mamy nadzieję, że ten samouczek pomoże Ci rozpocząć korzystanie z interfejsu API usług lokalizacyjnych Google.