返回索引目錄
原文鏈接:Location Services.
譯文鏈接:Xamarin.Android平台功能——位置服務
本部分介紹位置服務以及與如何使用位置提供商服務
Location Services
本教程將介紹如何在Android應用中定位,以及如何利用Android Location Service API來獲取用戶位置,同時還會通過Google Location Services API的位置服務來處理定位。
概述
Android提供多種定位技術接口,如利用蜂窩塔、WiFi和GPS。針對每一個定位技術的細節都已經被抽象為 location providers ,這使得應用可以通過一致的方法來獲取位置,而不用關心具體的服務實現。在本教程中,我們將介紹Android Location Service API,以及如何利用LocationManager來與系統位置服務進行通信。在教程的第二部分,我們會利用Google Location Services API —— 可用通過Google Play服務整合的定位功能來動態切換定位提供技術。
定位基礎
在Android中,無論你使用什么API來獲取定位數據,其中的基本概念是一致的。在本節中,我們將介紹位置提供程序和與位置相關的權限。
位置提供程序
有多種內置技術來精准定位用戶位置。要用到哪些硬件取決於選擇哪種類型的location provider來收集數據。Android中有以下三種位置提供程序:
- GPS Provider —— GPS定位最為精准,但耗電最多,且在室外定位最好。此提供程序組合使用GPS和輔助GPS(aGPS) —— 由蜂窩塔收集GPS數據並返回。
- Network Provider —— 提供程序組合使用WiFi和蜂窩數據,包括由蜂窩塔收集的aGPS數據。它耗電要比GPS Provider要少,但是它的定位精度會有所偏差。
- Passive Provider —— 使用由其他應用或服務生成的定位數據。這個數據不太可靠,但相對節能,在不需要經常更新位置信息的應用中是一個比較理想的方案。
位置提供程序並不是總是可用。例如,你可能需要在應用中使用GPS,但是GPS在設置中是關閉狀態,或者設備沒有GPS模塊支持。如果特定的提供程序不可用,選擇使用它會返回null值。
位置權限
一個定位應用需要訪問設備的硬件傳感器,以便於接收GPS,WiFi和蜂窩數據。訪問權限由應用的Android Manifest控制。其中涉及到了兩個權限 —— 這取決於你的應用要求和選擇了哪個API,你可以申請其中一個權限:
ACCESS_FINE_LOCATION—— 允許應用訪問GPS。在使用GPS Provider和Passive Provider選項時必需 —— Passive Provider要有訪問其他應用或服務收集的GPS數據的權限。在Netword Provider中,此權限可選。ACCESS_COARSE_LOCATION—— 允許應用訪問蜂窩或WiFi位置信息。在使用Network Provider時,如果沒有設置ACCESS_FINE_LOCATION,則此選項必需。
在目標為API版本為21(Android 5.0 Lollipop)或者更高版本中,應用可以在沒有GPS硬件模塊的設備上使用ACCESS_FINE_LOCATION權限。如果你的應用需要GPS硬件,你需要在Android Manifest中明確添加android.hardware.location.gps uses-feature元素。更多信息見:uses-feature element。
要設置權限,在解決方案管理器中,雙擊Properties,然后切換到Android Manifest標簽。Required Permissions部分為權限列表:
注:圖為官方文檔內的圖,上面的描述為Visual Studio操作描述。

設置這些權限會告訴Android,你的應用需要訪問那個定位技術的位置提供程序。
注意:設置了
ACCESS_FINE_LOCATION意味着包括了兩個定位數據權限。你不需要同時設置兩個權限,僅僅為你的應用設置最少要求的權限。
使用Android Location Service獲取位置信息
Android位置服務是Android中使用位置信息的標准API。位置數據是由硬件傳感器收集,並通過系統服務集中處理 —— 系統服務可以在應用中使用LocationManager類和ILocationListener來訪問。
為了通過Android位置服務獲取用戶位置,我們需要以下操作:
- 添加對LocationManager類的引用
- 使用LocationManager向特定的服務程序請求位置更新
- 實現ILocationListener接口,並在其中處理位置改變事件。
- 當應用進入后台時,停止位置更新。
位置服務
位置服務是系統中服務管理的一種特殊類型。系統服務和硬件設備交互,並一直保持運行。要在 我們的應用中使用位置更新,我們需要利用LocationManager和RequestLocationUpdates調用向系統位置服務請求位置更新。
位置管理
我們可以通過LocationManager類實例來訪問系統位置服務。LocationManager是一個特殊的類,它用於和系統位置服務交互,並通過它調用方法。應用可以通過調用GetSystemService來引用LocationManager,同時需要傳入一個服務類型,示例如下:
LocationManager locMgr;
...
locMgr = GetSystemService (Context.LocationService) as LocationManager;
OnCreate中比較適合創建LocationManager引用。將LocationManager定義為類的變量會比較好,這樣在Activity的生命周期中的各個點都可以調用它。
請求位置更新
一旦我們的應用創建了LocationManager引用,我們就需要告訴LocationManager我們需要什么類型的位置信息,以及我們要多久更新一次。我們可以通過調用LocationManager類對象的RequestionLocationUpdates方法(同時需要傳遞更新條件)來更新位置信息。
RequestionLocationUpdates方法告訴系統位置服務,你的應用需要開始接收位置更新。此方法語句你指定提供程序,以及控制更新頻率的時間和距離閾值。例如,如下代碼,要求每2000毫秒請求一次位置更新,並且只有當位置更改超過1米時才更新:
protected override void OnResume ()
{
base.OnResume ();
string Provider = LocationManager.GpsProvider;
if(locMgr.IsProviderEnabled(Provider))
{
locMgr.RequestLocationUpdates (Provider, 2000, 1, this);
}
else
{
Log.Info(tag, Provider + " is not available. Does the device have location services enabled?");
}
}
應用程序應該按照需要控制執行請求位置更新。這可以延長電池壽命,同時為用戶提供更好的體驗。
訂閱位置更新
一旦應用通過LocationManager請求了位置更新,它可以通過實現ILocationListener接口來接受服務提供的信息。此接口提供監控位置服務和位置提供程序的方法。
以下代碼示例為在MainActivity中實現ILocationListener:
public class MainActivity : Activity, ILocationListener
{
...
public void OnProviderEnabled (string provider)
{
...
}
public void OnProviderDisabled (string provider)
{
...
}
public void OnStatusChanged (string provider, Availability status, Bundle extras)
{
...
}
public void OnLocationChanged (Android.Locations.Location location)
{
...
}
}
此接口讓我們可以訂閱四個系統事件,以供檢測提供程序狀態和獲取位置信息:
- OnProviderEnabled和OnProviderDisabled —— 互補方法,當用戶啟用或禁用提供程序時通知。(例如:用戶可能禁用GPS來省電)。
- OnStatusChanged —— 當提供程序可用性發生改變時通知,同時還提供相應的狀態。(例如:當用戶進入室內時,GPS的可用性可能會發生改變)
- OnLocationChanged —— 當用戶位置改變情況滿足我們設置的更新條件時,系統調用OnLocationChanged。
以下代碼示例說明了Activity應該如何實現OnLocationChanged方法來接收位置更新,並將其顯示到界面:
TextView latitude;
TextView longitude;
public void OnLocationChanged (Location location)
{
latitude.Text = "Latitude: " + location.Latitude;
longitude.Text = "Longitude: " + location.Longitude;
}
停止位置更新
RemoveUpdates方法告訴系統位置服務停止發送更新數據到我們的應用。在OnPause中調用此方法,當應用的Activity不在前台顯示時,應用移除位置更新可以節省電量:
protected override void OnPause ()
{
base.OnPause ();
locMgr.RemoveUpdates (this);
}
如果你的應用需要在后台仍可已獲取位置更新,你需要創建一個定制服務來訂閱系統位置服務。關於后台服務的信息見:原文:Backgrounding with Android Services。
獲取最好的提供程序
上述示例使用GPS作為位置提供程序。但是,GPS並不是所有情況下都可用,例如,設備處於室內或設備沒有GPS接收器。如果是這種情況,我們會從提供程序獲得null值。
如果我們想要我們的應用在GPS不可用的情況下工作,我們可以應用啟動時使用GetBestProvider方法獲取最好且可用(設備支持且用戶啟用)的位置提供程序。我們可以通過告訴GetBestProvider方法我們的提供程序要求來取代直接傳遞指定的提供程序。例如:傳入精度和耗電要求 —— 使用Criteria對象,這樣GetBestProvider會通過給定的Criteria來返回最適合的提供程序。
以下代碼展示了如何獲得最合適的提供程序,以及在請求位置更新時,如何使用它:
Criteria locationCriteria = new Criteria();
locationCriteria.Accuracy = Accuracy.Coarse;
locationCriteria.PowerRequirement = Power.Medium;
locationProvider = locMgr.GetBestProvider(locationCriteria, true);
if(locationProvider != null)
{
locMgr.RequestLocationUpdates (locationProvider, 2000, 1, this);
}
else
{
Log.Info(tag, "No location providers available");
}
注意:如果用戶禁用了所有位置提供程序,GetBestProvider將會返回null值。
為了展示代碼如何在真實設備上工作,請確保GPS,WiFi和蜂窩網絡啟用。可以如截圖顯示設置:Google設置——位置——模式

如下截圖演示了利用GetBestProvider獲取位置的位置應用:

請記住,GetBestProvider不會動態更新提供程序。相反,它在Activity的生命周期中只確定一次最佳提供程序。如果在已經獲取過提供程序后,提供程序狀態發生了變化,應用則需要為ILocationListener中的方法(OnProviderEnabled, OnProviderDisabled, 和 OnStatusChanged)添加額外的代碼來處理提供程序的切換。
為了使常見場景變得簡單,以及使用較少的代碼,Google為我們引入了FusedLocationProvider來處理提供程序的改變。FusedLocationProvider是Google位置服務API的一部分,Google位置服務是附加在Google Play服務上的。我們將在下面介紹它。
通過Google位置服務和FusedLocationProvide獲取位置
由於國內大部分廠商提供的Android機都沒有Google服務,故此處暫不做翻譯。
原文見:Get Location with Google Location Services and the Fused Location Provider。
原文示例代碼
譯:奇葩史
