文章目錄
1、概述
地理定位的方式有四種:wifi, ip地址, 手機基站, GPS。
win8內建了wifi, ip地址兩種方式,wifi定位的精度在350米左右,ip地址的精度在25千米。
win8定位服務不提供朝向,高度,速度,地址等資料。
當需要用定位服務時,需要顯式地提醒使用者,並在window8的隱私權設定裡開啟定位服務。
- 在應用能力裡開啟位置服務。
2、指導方針
只調用一次定位的請求,用getGeopostionAsync()方法。
設定軌跡資料變化閾值,通過設定MovementThreshold屬性,當在此值的範圍之外變化時,才觸發PositionChanged事件,比如城市間的天氣變化。
設定位置資料報告頻率,通過設定ReportInterval屬性,為0時,則即時變化。注意:有些裝置設定此屬性可能無用。
設定精度,通過設定DesiredAccuracy屬性,當精度為高時,才會調用GPS。
啟動延遲,可能會有2秒,注意不要阻塞UI。
後台運行,當應用掛起時,資料不會更新,所以考慮後台運行。
- 捕獲StatusChanged事件,瞭解位置服務可用狀態。
- 當使用者禁止了位置服務時,調用getGeopostionAsync()會報異常,LocationStatus值是disable,這時需要提醒使用者去開啟位置服務。
- 當狀態不可用時,應該清除快取資料。
- 當使用者重新開啟位置功能時,不會有任何事件產生,只有依靠程式請求資料來得到這個事件。
- 當應用從掛起到啟用時,應當重新擷取位置資料。
- 提供一個重新整理按鈕讓使用者去重新擷取位置資料。
- 建議提示"Your location is currently turned off. Change your settings through the Settings charm to turn it back on.”
- 如果位置不是重要訊息,就用通知就行,如果位置是重要訊息,比如地圖,就用flyout.
3、C#樣本
擷取位置資料
using System;using System.Collection.Generic;using System.Linq;using System.Threading.Tasks;using Windows.Foundation;using Windows.UI.DirectUI;using Windows.UI.DirectUI.Controls;using Windows.UI.DirectUI.Data;using Windows.Devices.Geolocation;namespace GeolocationSample{ partial class MainPage { Geolocator geo = null; public MainPage() { InitializeComponent(); } private async void button1_Click( object sender, RoutedEventArgs e) { if (geo == null) { geo = new Geolocator(); } IGeoposition pos = await geo.GetGeopositionAsync(); textblockLatitude.Text = "Latitude: " + pos.Coordinate.Latitude.ToString(); textblockLongitude.Text = "Longitude: " + pos.Coordinate.Longitude.ToString(); textblockAccuracy.Text = "Accuracy: " + pos.Coordinate.Accuracy.ToString(); } }}
擷取位置變化情況資料
using System;using System.Collection.Generic;using System.Linq;using System.Threading.Tasks;using Windows.Foundation;using Windows.UI.Core;using Windows.UI.DirectUI;using Windows.UI.DirectUI.Controls;using Windows.UI.DirectUI.Data;using Windows.Devices.Geolocation; namespace GeolocationEventsSample{ partial class MainPage { private Geolocator geo = null; private CoreDispatcher _cd; public MainPage() { InitializeComponent(); _cd = Window.Current.CoreWindow.Dispatcher; } private void button1_Click(object sender, RoutedEventArgs e) { if (geo == null) { geo = new Geolocator(); } if (geo != null) { geo.PositionChanged += new TypedEventHandler<Geolocator, PositionChangedEventArgs>(geo_PositionChanged); } } private void button2_Click(object sender, RoutedEventArgs e) { if (geo != null) { geo.PositionChanged -= new TypedEventHandler<Geolocator, PositionChangedEventArgs> (geo_PositionChanged); } } private void geo_PositionChanged(Geolocator sender, PositionChangedEventArgs e) { _cd.InvokeAsync(CoreDispatcherPriority.Normal, (s, a) => { IGeoposition pos = (a.Context as IPositionChangedEventArgs).Position; textLatitude.Text = "Latitude: " + pos.Coordinate.Latitude.ToString(); textLongitude.Text = "Longitude: " + pos.Coordinate.Longitude.ToString(); textAccuracy.Text = "Accuracy: " + pos.Coordinate.Accuracy.ToString(); }, this, e); } }}
設定位置資料變化閾值
using System;using System.Collections.Generic;using System.IO;using System.Linq;using Windows.Foundation;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;using Windows.UI.Core;using Windows.Devices.Geolocation;// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238namespace GeolocationAdjustDistance{ /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class BlankPage : Page { private Geolocator geo = null; private CoreDispatcher _cd; private double prevLatitude = -1; private double prevLongitude = -1; private double totalDistance = 0; public BlankPage() { this.InitializeComponent(); _cd = Window.Current.CoreWindow.Dispatcher; } /// <summary> /// Invoked when this page is about to be displayed in a Frame. /// </summary> /// <param name="e">Event data that describes how this page was reached. The Parameter /// property is typically used to configure the page.</param> protected override void OnNavigatedTo(NavigationEventArgs e) { } private void Button_Click_1(object sender, RoutedEventArgs e) { if (geo == null) { geo = new Geolocator(); } if (geo != null) { geo.PositionChanged += new TypedEventHandler<Geolocator, PositionChangedEventArgs>(geo_PositionChanged); geo.StatusChanged += new TypedEventHandler<Geolocator, StatusChangedEventArgs>(geo_StatusChanged); geo.MovementThreshold = float.Parse(tbThreshold.Text); tbThreshold.IsEnabled = false; TextBox1.Text = "Tracking Started " + "(Time, Latitude, Longitude, Distance)\n"; } } private void Button_Click_2(object sender, RoutedEventArgs e) { if (geo != null) { geo.PositionChanged -= new TypedEventHandler<Geolocator, PositionChangedEventArgs>(geo_PositionChanged); geo.StatusChanged -= new TypedEventHandler<Geolocator, StatusChangedEventArgs>(geo_StatusChanged); TextBox1.Text += "\nTracking Stopped.\n" + "Total Distance recorded: " + totalDistance.ToString("F2") + " m\n"; tbThreshold.IsEnabled = true; } } private double CalculateDistance(double prevLat, double prevLong, double currLat, double currLong) { const double degreesToRadians = (Math.PI / 180.0); const double earthRadius = 6371; // kilometers // convert latitude and longitude values to radians var prevRadLat = prevLat * degreesToRadians; var prevRadLong = prevLong * degreesToRadians; var currRadLat = currLat * degreesToRadians; var currRadLong = currLong * degreesToRadians; // calculate radian delta between each position. var radDeltaLat = currRadLat - prevRadLat; var radDeltaLong = currRadLong - prevRadLong; // calculate distance var expr1 = (Math.Sin(radDeltaLat / 2.0) * Math.Sin(radDeltaLat / 2.0)) + (Math.Cos(prevRadLat) * Math.Cos(currRadLat) * Math.Sin(radDeltaLong / 2.0) * Math.Sin(radDeltaLong / 2.0)); var expr2 = 2.0 * Math.Atan2(Math.Sqrt(expr1), Math.Sqrt(1 - expr1)); var distance = (earthRadius * expr2); return distance * 1000; // return results as meters } void geo_PositionChanged(Geolocator sender, PositionChangedEventArgs args) { _cd.InvokeAsync(CoreDispatcherPriority.Normal, (s, a) => { Geoposition pos = (a.Context as IPositionChangedEventArgs).Position; double updateDistance = 0; // Calculate distance; if ( ( prevLatitude == -1 ) || ( prevLongitude == -1 ) ) { updateDistance = 0; } else { updateDistance = CalculateDistance( prevLatitude, prevLongitude, pos.Coordinate.Latitude, pos.Coordinate.Longitude ); } // Update tracking prevLatitude = pos.Coordinate.Latitude; prevLongitude = pos.Coordinate.Longitude; totalDistance += updateDistance; // display the results. TextBox1.Text += "Position Update: " + pos.Coordinate.Timestamp.ToString("T") + ", " + pos.Coordinate.Latitude.ToString("F3") + ", " + pos.Coordinate.Longitude.ToString("F3") + ", " + updateDistance.ToString("F2") + " m\n"; }, this, args); } void geo_StatusChanged(Geolocator sender, StatusChangedEventArgs args) { var newStatus = args.Status; var strStatus = ""; switch (newStatus) { case PositionStatus.Ready: strStatus = "Location is available."; break; case PositionStatus.Initializing: strStatus = "Geolocation service is initializing."; break; case PositionStatus.NoData: strStatus = "Location service data is not available."; break; case PositionStatus.Disabled: strStatus = "Location services are disabled. Use the " + "Settings charm to enable them."; break; case PositionStatus.NotInitialized: strStatus = "Location status is not initialized because " + "the app has not yet requested location data."; break; case PositionStatus.NotAvailable: strStatus = "Location services are not supported on your system."; break; default: strStatus = "Unknown PositionStatus value (" + newStatus.ToString() + ")."; break; } _cd.InvokeAsync(CoreDispatcherPriority.Normal, (s, a) => { TextBox1.Text += strStatus + "\n"; }, this, args); } }}