Windows phone 8 基于定位的后台应用
后台应用算是 windows phone 8 所特有的一个新功能,说起后台我经常要和地图一起聊起 【关于地图的用法请参考:Windows Phone 8 Nokia地图控件 】今天我着重跟大家聊一下手机定位及基于定位的后台应用,说到定位相信大家已经不再陌生,下载各个平台的只能手机定位 GPS & AGPS 都是一个基本功能很多应用都会用到,但是后台定位应用可能有些同学不他理解,我举一个“栗子”说,好比我现在开车正在借助一款手机导航软件寻找某个餐馆,此时家里的那位老大已经到了目的地要检查一下我到哪了,于是电话响了。。。这时导航软件必然被切换到后台,相信用过手机导航的同学都有过这样的经历,如此场景其他平台也就罢了,在如今windows phone8 是应用支持后台的,那么这个后台能做什么呢?简单的说也就是在此场景下应用可以通过其他形式的提醒方式继续为用户提供导航,例如 ShellToast 当然后台能够使用的API是受限制 但是也足够用了 API的限制请相信参考MSDN:http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj662941(v=vs.105).aspx
此文是 升级到WP8必需知道的13个特性 系列的一个更新 希望这个系列可以给 Windows Phone 8开发者带来一些开发上的便利。
同时欢迎大家在这里和我沟通交流或者在新浪微博上 @王博_Nick
首先我先给大家介绍如使用定位
使用定位功能当然还是要在Manifest文件中声明 location 这里我用的是上一节的Demo 所以也选中了MAP如果你的应用没有使用地图控件可以不选MAP,
这里介绍一下 Geolocator 这个对象使用它来对地理位置进行获取、初始精度、追踪状态等。
private void TrackLocation_Click_1(object sender, EventArgs e) { if (!tracking) { App.Geolocator = new Geolocator(); App.Geolocator.DesiredAccuracy = PositionAccuracy.High; App.Geolocator.MovementThreshold = 2; // The units are meters. App.Geolocator.StatusChanged += geolocator_StatusChanged; App.Geolocator.PositionChanged += geolocator_PositionChanged; tracking = true; //TrackLocationButton.Content = "stop tracking"; } else { App.Geolocator.PositionChanged -= geolocator_PositionChanged; App.Geolocator.StatusChanged -= geolocator_StatusChanged; App.Geolocator = null; tracking = false; //TrackLocationButton.Content = "track location"; StatusTextBlock.Text = "stopped"; } }
下面主要使用了StatusChange 和 PositionChange 时间来进行位置获取和路径追踪。
注释中可以明确的看到返回的枚举值都代表着目前是什么样的一个状态,注意这里包括获取到用户在 系统设置中禁用了定位服务(之前有朋友问过我这个问题)
void geolocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args) { string status = ""; switch (args.Status) { case PositionStatus.Disabled: // the application does not have the right capability or the location master switch is off status = "location is disabled in phone settings"; break; case PositionStatus.Initializing: // the geolocator started the tracking operation status = "initializing"; break; case PositionStatus.NoData: // the location service was not able to acquire the location status = "no data"; break; case PositionStatus.Ready: // the location service is generating geopositions as specified by the tracking parameters status = "ready"; break; case PositionStatus.NotAvailable: status = "not available"; // not used in WindowsPhone, Windows desktop uses this value to signal that there is no hardware capable to acquire location information break; case PositionStatus.NotInitialized: // the initial state of the geolocator, once the tracking operation is stopped by the user the geolocator moves back to this state break; } Dispatcher.BeginInvoke(() => { StatusTextBlock.Text = status; }); }
PositionChange 中的代码是上次讲地图的时候写的code添加了一个图层来标记当前位置,当然 args.Position.Coordinate 中的属性就是我们想得到的经纬度信息了
void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args) { Dispatcher.BeginInvoke(() => { if (!MyMap.MapElements.Contains(MPL)) MyMap.MapElements.Add(MPL); CurrenLocation = new GeoCoordinate(args.Position.Coordinate.Latitude, args.Position.Coordinate.Longitude); MPL.Path.Add(CurrenLocation); MyMap.SetView(CurrenLocation, 15, MapAnimationKind.Parabolic); MyMap.Layers.Clear(); MapOverlay MyOverlay = new MapOverlay(); MyOverlay.Content = GetGrid(); MyOverlay.GeoCoordinate = new GeoCoordinate(CurrenLocation.Latitude, CurrenLocation.Longitude); MyOverlay.PositionOrigin = new Point(0, 0.5); MapLayer MyLayer = new MapLayer(); MyLayer.Add(MyOverlay); MyMap.Layers.Add(MyLayer); }); }
其次再给大家介绍如何使应用在后台继续跟踪定位
上面我只是实现了一个定位应用和WP7样的在后台不会继续工作,接下来我对这个项目稍作修改 让大家看看怎么做一个基于定位的后台应用。
首先呢我们需要手动修改Manifest文件,也就是右键Manifest文件文本编辑,在Tasks 下 DefaultTask节点中添加 BackgroundExecution节点如下:
<Tasks> <DefaultTask Name="_default" NavigationPage="MainPage.xaml"> <BackgroundExecution> <ExecutionType Name="LocationTracking" /> </BackgroundExecution> </DefaultTask> </Tasks>
之后呢我们打开 项目文件中的 App.xaml 在shell:PhoneApplicationService 中注册 RuningInBackground 事件用来标记此应用以及跑在后,并且我们声明两个静态属性 分别是 Geolocator 和 RunningInBackground,作用是在应用程序中共享状态。
public static Geolocator Geolocator { get; set; } public static bool RunningInBackground { get; set; } private void Application_RunningInBackground(object sender, RunningInBackgroundEventArgs args) { RunningInBackground = true; // Suspend all unnecessary processing such as UI updates } private void Application_Activated(object sender, ActivatedEventArgs e) { RunningInBackground = false; }
分别在声明周期的 RunningInBackground 和 Activated 事件中标记应用程序的后台运行情况,细心的同学可能已经发现我在前面声明 Geolocator 的时候已经是赋值给 App.Geolocator 以确保在后台也可以持续访问该对象
另外还要额外处理一下页面的 OnRemovedFromJournal 事件以确保再次访问此页面的时候讲从新创建新的实例:
protected override void OnRemovedFromJournal(System.Windows.Navigation.JournalEntryRemovedEventArgs e) { App.Geolocator.PositionChanged -= geolocator_PositionChanged; App.Geolocator = null; }
同时更新代码 StatusChanged
void geolocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args) { string status = ""; switch (args.Status) { case PositionStatus.Disabled: // the application does not have the right capability or the location master switch is off status = "location is disabled in phone settings"; break; case PositionStatus.Initializing: // the geolocator started the tracking operation status = "initializing"; break; case PositionStatus.NoData: // the location service was not able to acquire the location status = "no data"; break; case PositionStatus.Ready: // the location service is generating geopositions as specified by the tracking parameters status = "ready"; break; case PositionStatus.NotAvailable: status = "not available"; // not used in WindowsPhone, Windows desktop uses this value to signal that there is no hardware capable to acquire location information break; case PositionStatus.NotInitialized: // the initial state of the geolocator, once the tracking operation is stopped by the user the geolocator moves back to this state break; } Dispatcher.BeginInvoke(() => { StatusTextBlock.Text = status; }); if (App.RunningInBackground) { Microsoft.Phone.Shell.ShellToast toast = new Microsoft.Phone.Shell.ShellToast(); toast.Title = "Location: "; toast.Content = args.Status.ToString(); toast.NavigationUri = new Uri("/MainPage.xaml", UriKind.Relative); toast.Show(); } }
和 PositionChanged
void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args) { if (App.RunningInBackground) { Microsoft.Phone.Shell.ShellToast toast = new Microsoft.Phone.Shell.ShellToast(); toast.Title = "Location is "; toast.Content = "Latitude: " + args.Position.Coordinate.Latitude.ToString("0.00") + " Longitude: " + args.Position.Coordinate.Longitude.ToString("0.00"); toast.NavigationUri = new Uri("/MainPage.xaml", UriKind.Relative); toast.Show(); } Dispatcher.BeginInvoke(() => { if (!MyMap.MapElements.Contains(MPL)) MyMap.MapElements.Add(MPL); CurrenLocation = new GeoCoordinate(args.Position.Coordinate.Latitude, args.Position.Coordinate.Longitude); MPL.Path.Add(CurrenLocation); MyMap.SetView(CurrenLocation, 15, MapAnimationKind.Parabolic); MyMap.Layers.Clear(); MapOverlay MyOverlay = new MapOverlay(); MyOverlay.Content = GetGrid(); MyOverlay.GeoCoordinate = new GeoCoordinate(CurrenLocation.Latitude, CurrenLocation.Longitude); MyOverlay.PositionOrigin = new Point(0, 0.5); MapLayer MyLayer = new MapLayer(); MyLayer.Add(MyOverlay); MyMap.Layers.Add(MyLayer); }); }
之后我们启动应用程序
打开模拟器的 Additional tools中的location来模拟地理位置的变化,当然实现要把我们的程序切如后台。
运行效果如下:
好了相信大家看过之后在 windows phone 8 中实现一个基于定位的后台应用已经有了一个了解,欢迎大家在这里和我沟通交流或者在新浪微博上 @王博_Nick