Google 定位服務 API 的 Android 開發者指南

已發表: 2022-03-11

在我們今天開發和使用的許多應用程序中,了解用戶的位置是有用的信息。 有很多流行的基於位置的應用程序讓我們的生活更輕鬆,並改變了我們使用這些服務的方式。 一個例子是廣受歡迎的應用程序 Foursquare,經常去機構和“簽到”的用戶通常會贏得折扣。 優步,它可以幫助您以比普通出租車更低的價格通過手機打車。 這份名單很大,而且還在增長。

定位服務 API

在本文中,我們將構建一個簡單的 Android 應用程序,以使用 Android 的 Google Location Services API 確定用戶的緯度和經度。 在開發 Android 應用程序時,有幾種方法可以獲取用戶的位置。

包“android.location”

自 Android 首次引入以來,“android.location”包就已可用,它使我們能夠訪問位置服務。 這些服務允許應用程序獲取設備地理位置的定期更新。

該軟件包提供了兩種獲取位置數據的方法:

  • LocationManager.GPS_PROVIDER:使用衛星確定位置。 根據條件,此提供程序可能需要一段時間才能返回位置修復。

  • LocationManager.NETWORK_PROVIDER:根據附近蜂窩塔和 WiFi 接入點的可用性確定位置。 這比 GPS_PROVIDER 快。

當您在尋找用戶位置時,您必須與這些提供商及其可用性進行比較。 理想情況下,您使用 NETWORK_PROVIDER 獲得第一個位置,這可能不那麼準確,但要快得多。 然後,您可以嘗試通過使用 GPS_PROVIDER 偵聽更好的位置修復來提高準確性。

此包提供的 API 相當低級,需要應用程序的開發人員處理更精細的細節,以確定何時請求位置數據並以優化的方式安排對 API 的調用。 為了改善開發人員使用基於位置的系統服務的體驗並簡化開發位置感知應用程序的過程,Google 引入了一種使用 Google Play 服務請求用戶位置的新方法。 它提供了一個更簡單的 API,具有更高的準確性、低功耗地理圍欄等等。

谷歌定位服務 API

Google Location Services API,也稱為 FusedLocationProviderApi,是 Google 推薦的獲取用戶位置的方法。 它根據我們的需要提供最佳精度。 與前一個 API 相比,使用此 API 的一些優點是:

  • 簡單性:與以前的 API 不同,您不再需要處理多個提供程序。 相反,您指定高級需求,例如“高精度”或“低功耗”,它將採取合適的方法。

  • 可用性:讓您的應用立即訪問最佳、最近的已知位置。 通常這些信息很容易獲得,您只需要索取即可。

  • 電源效率:最大限度地減少應用程序的電源使用。

  • 多功能性:滿足廣泛的需求,從前台使用 - 需要高度準確的位置數據,到後台使用 - 只需要定期更新位置,而對電源的影響可以忽略不計。

讓我們使用這個 API 構建一個基於位置的 Android 應用程序。 為此,我們將使用 Google 推薦的用於 Android 應用程序開發的 IDE——Android Studio。 Android Studio 入門非常簡單。 他們的網站非常詳細地描述了涉及安裝和配置 Android Studio 的過程,包括如何引導您的第一個 Android 應用程序進行開發。

Android Studio 應該讓我們的事情變得超級簡單。 但是,我們需要首先配置構建腳本並添加 Google Play 服務作為此應用程序的依賴項。 這可以通過如下修改“build.gradle”文件來完成:

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

在我撰寫本文時,可用的最新版 Google Play 服務是 6.5.87。 確保在開始之前始終檢查可用的最新版本。 萬一較晚的版本出現並且您決定為自己的項目更新它,請針對您支持的所有 Android 版本測試所有與位置相關的功能。

此時,我們應該可以開始為我們的應用程序做實際的工作了。

請求權限,配置AndroidManifest.xml

Android 具有特定的安全功能,可以防止任意應用程序請求精確的用戶位置。 為了解決這個問題,我們需要編輯“AndroidManifest.xml”並添加我們需要的這個應用程序的權限:

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

在此過程中,我們還應該定義用於此應用程序的 Google Play 服務版本:

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

檢查 Google Play 服務的可用性

在訪問 Google Play 服務提供的功能之前,我們必須檢查設備是否安裝了 Google Play 服務,並且該版本是我們打算使用的版本(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; }

此方法將檢查 Google Play 服務,如果設備沒有安裝它(這種情況很少見,但我見過這種情況),它將打開一個帶有相應錯誤的對話框並邀請用戶安裝/更新來自 Google Play 商店的 Google Play 服務。

谷歌播放服務

用戶完成“GooglePlayServicesUtil.getErrorDialog()”提供的解析後,會觸發回調方法“onActivityResult()”,因此我們必須實現一些邏輯來處理該調用:

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

訪問 Google API

要訪問 Google API,我們只需要再執行一步:創建 GoogleApiClient 的實例。 Google API 客戶端為所有 Google Play 服務提供了一個公共入口點,並管理用戶設備與每個 Google 服務之間的網絡連接。 我們的第一步是啟動連接。 我通常從活動的“onCreate”方法調用這段代碼:

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

通過鏈接一系列方法調用,我們指定了回調接口實現和我們想要使用的位置服務 API。 當與 Google Play 服務的連接成功、失敗或掛起時,接口實現(在本例中為“this”)將接收對異步“connect()”方法的響應。 添加此代碼後,我們的“MainActivity”應如下所示:

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

然後在我們的“onStart”方法中調用“connect”方法並等待“onConnected”回調方法被調用:

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

“onConnected”方法如下所示:

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

連接 Google Play 服務時會觸發此回調,這意味著到那時我們應該有最後一個已知位置。 但是,此位置可以為空(這種情況很少見,但並非不可能)。 在這種情況下,我建議收聽位置更新,這將在接下來介紹。

監聽位置更新

調用“getLastLocation”後,您可能希望從 Fused Location Provider 請求定期更新。 根據您的應用程序,這段時間可能很短也可能很長。 例如,如果您正在構建一個在用戶開車時跟踪用戶位置的應用程序,您將需要在短時間內偵聽更新。 另一方面,如果您的應用程序是關於與他的朋友分享用戶位置,您可能只需要偶爾請求一次位置。

創建請求非常簡單——你可以在“onCreate”方法中調用這個方法:

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

我們實例化一個新的 LocationRequest 對象。 將時間間隔設置為 20 秒(20000 毫秒)。 此外,我們將限制更新速率設置為 5 秒。 這告訴 API 每 20 秒(最好)提供一次更新,但如果在 5 秒內有可用的更改,它也應該提供。 最後,我們將優先級設置為“PRIORITY_HIGH_ACCURACY”,以及其他可用的優先級選項:PRIORITY_BALANCED_POWER_ACCURACY、PRIORITY_LOW_POWER、PRIORITY_NO_POWER。

一旦你建立了請求,你就可以在“onConnected()”方法被觸發後開始監聽位置更新:

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

現在剩下的就是實現回調方法來滿足 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(); } } 

停止收聽更新

停止監聽更新

當您不再需要更新或用戶離開您的應用程序時,顯式停止偵聽更新非常重要。 應從“onPause”回調中調用以下方法:

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

... 並斷開 Google API:

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

包起來

如您所見,在 Android 中實現位置感知應用程序背後的基本思想非常簡單。 此外,使用簡單易用且易於理解的可用 API,為 Android 構建基本的基於位置的應用程序應該是輕而易舉的事。 我們在此處構建的小型示例應用程序旨在準確地展示這一點。 你可以在 GitHub 上找到完整的源代碼。 請注意,為簡單起見,應用程序不處理“onConnectionFailed”回調方法。

希望本教程能幫助您開始使用 Google 位置服務 API。