This blog post was authored by Daniel Estrada Alva, a software development engineer on the Windows Phone team.
- Adam
In this post I describe how you can optionally modify your Windows Phone 7 geolocation code to use the new Windows Runtime (WinRT) Geolocation APIs in Windows Phone 8. Modifying your code to use the new Geolocation APIs in Windows Phone 8 is optional, but offers some solid advantages. In future posts I’ll go into more detail about the extended functionality that the new APIs offer, and how to implement the Windows Runtime. I’ll also walk you through some scenarios that you can build into your Windows Phone 8 apps.
Windows Phone 8 offers a set of APIs in the new namespace Windows.Devices.Geolocation. The following table maps the types of the new Windows Phone 8 APIs to types of the set of APIs provided in the namespace System.Device.Location in Windows Phone 7:
Windows.Devices.Geolocation [Windows Phone 8] | System.Device.Location [Windows Phone 7] |
Geolocator | GeoCoordinateWatcher |
Geoposition | GeoPosition |
Geocoordinate | GeoCoordinate |
[Not implemented in Windows Phone 8] | CivicAddress |
Each Windows Phone 8 WinRT API provides the same functionality as the Windows Phone 7 API it replaces. However, Windows Phone 8 APIs also give you new ways to define your positioning requirements. Now you can use fewer requests to accomplish your objective. The following table summarizes the functionality in the Windows Phone 8 namespace Windows.Devices.Geolocation.Geolocator:
Windows.Devices.Geolocation.Geolocator member | Function |
DesiredAccuracy | Sets the accuracy requirements through an enumeration with common values. |
DesiredAccuracyInMeters | (NEW) Provides a more granular way to define your accuracy requirements. |
MovementThreshold | Sets the movement threshold, in meters, at which the app should be notified. |
ReportInterval | (NEW) Sets the time interval at which the app expects to receive periodic position notifications. |
PositionChanged event | Provides notifications when a position update is available. Position updates are available depending on the parameters specified for the session. |
StatusChanged event | Provides notifications when the status of a tracking session changes. |
GetGeopositionAsync() | (NEW) Asynchronous operation through which an app can obtain a single position update. |
GetGeopositionAsync() MaximumAge Timeout | (NEW) Asynchronous operation through which an app can obtain a single position update. In addition, you can specify how long to wait for the results of the operation (Timeout), and the maximum age of cached position data (MaximumAge). |
The following table compares Windows.Devices.Geolocation.Geolocator and System.Device.Location.GeoCoordinateWatcher members:
Windows.Devices.Geolocation.Geolocator member | System.Device.Location.GeoCoordinateWatcher member |
DesiredAccuracy | DesiredAccuracy |
MovementThreshold | MovementThreshold |
[ NOT NEEDED: You can use GetGeopositionAsync(Age, Timeout) to obtain the same results; see the following example.] | Position |
LocationStatus | Status |
PositionChanged | PositionChanged |
StatusChanged | StatusChanged |
[NOT NEEDED] | Start() |
[NOT NEEDED] | Stop() |
[NOT NEEDED] | Dispose() |
[NOT NEEDED] | TryStart() |
TryStart() and any other synchronous behaviors have been removed from the new interfaces in favor of the WinRT asynchronous model in Windows Phone 8.
Some tips:
- The signatures of the PositionChanged and StatusChanged events have changed. The new API passes in the Geolocator object that generated the event as its concrete type instead of as a System.Object as it does in the Windows Phone 7 API.
- Start/Stop are now implicit to the Add/Remove operations for the PositionChanged and StatusChanged events.
- The Geolocator object doesn’t implement IClosable (which is the equivalent to IDisposablein the .NET Framework), so it relies mostly on event handlers to be removed when the tracking operation isn’t needed. To stop tracking, you need to unregister the event handlers before the Geolocator object is thrown away. Make sure you don’t forget to do this!
- Remember that a tracking operation can be expensive, in terms of battery consumption. Use the new asynchronous GetGeopositionAsync method to get a single position update if you only care about detecting the current position (see the GetGeopositionAsync sample below).
The following code snippet is an example of how your code may look in Windows Phone 7:
- private GeoCoordinateWatcher geoCoordinateWatcher;
- publicvoid StartTracking()
- {
- if (this.geoCoordinateWatcher != null)
- {
- return;
- }
- this.geoCoordinateWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
- this.geoCoordinateWatcher.MovementThreshold = 100; // in meters
- this.geoCoordinateWatcher.PositionChanged += (watcherSender, eventArgs) =>
- {
- // ...
- };
- geoCoordinateWatcher.Start();
- }
- publicvoid StopTracking()
- {
- if (geoCoordinateWatcher == null)
- {
- return;
- }
- geoCoordinateWatcher.Stop();
- geoCoordinateWatcher.Dispose();
- geoCoordinateWatcher = null;
- }
The following is how your code will look with the new APIs. Note that you no longer need to provide the accuracy you require in the constructor. You also can modify the property on the object as long as a tracking operation is not in progress.
- private Geolocator trackingGeolocator;
- private TypedEventHandler
positionChangedHandler; - publicvoid StartTracking()
- {
- if (this.trackingGeolocator!= null)
- {
- return;
- }
- this.trackingGeolocator = new Geolocator();
- this.trackingGeolocator.MovementThreshold = 100; // in meters
- if (this.positionChangedHandler != null)
- {
- this.positionChangedHandler = (geolocator, eventArgs) =>
- {
- // ...
- };
- }
- this.trackingGeolocator.PositionChanged += positionChangedHandler;
- }
- publicvoid StopTracking()
- {
- if (this.trackingGeolocator == null)
- {
- return;
- }
- this.trackingGeolocator.PositionChanged -= this.positionChangedHandler;
- this.trackingGeolocator = null;
- }
The StatusChanged API hasn’t changed, so I don’t show it here. The list of supported statuses is listed here for reference: http://msdn.microsoft.com/en-US/library/windows/apps/windows.devices.geolocation.geolocator.statuschanged .
Finally, the Geolocator object is a simple way to get a single position update asynchronously. You can also simplify your code with this API if you only need the current position of the device. Here’s an example of how your code may look on Windows Phone 7:
- public GeoCoordinate GetSingleLocation()
- {
- GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
- EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
- GeoCoordinate geoCoordinate = null;
- geoCoordinateWatcher.PositionChanged += (watcherSender, eventArgs) =>
- {
- geoCoordinate = eventArgs.Position.Location;
- waitHandle.Set();
- };
- geoCoordinateWatcher.Start();
- waitHandle.WaitOne();
- geoCoordinateWatcher.Stop();
- geoCoordinateWatcher.Dispose();
- return geoCoordinate;
- }
When you use the new GetGeopositionAsync() API, you can leverage the new await operator (http://msdn.microsoft.com/en-us/library/hh156528.aspx) to significantly simplify your code:
- publicasyncTask
GetSinglePositionAsync() - {
- Geolocator geolocator = new Geolocator();
- geolocator.DesiredAccuracy = PositionAccuracy.High;
- Geoposition geoposition = await geolocator.GetGeopositionAsync();
- return geoposition.Coordinate;
- }
We will be adding follow-up posts that take a deeper look at the new APIs, and how you can use them in advanced scenarios in your Windows Phone 8 apps.