返回索引目录
原文链接: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。
原文示例代码
译:奇葩史