The Geolocator
class can be used by your app to monitor the location of the phone. It contains events for monitoring hardware state changes and geographic position changes.
Geolocator
allows you to track the phone’s location, using its PositionChanged
event, and to retrieve the phone’s current location using its GetGeopositionAsync
method.
The GetGeopositionAsync
method forgoes the need to subscribe to the PositionChanged
event when all you need is a single reading. With GetGeopositionAsync
you can use the await keyword to conveniently wait for the method to return the Geoposition
result, as shown in the following example:
var geolocator = new Geolocator();
Geoposition geoposition = await geolocator.GetGeopositionAsync();
Geocoordinate geocoordinate = geoposition.Coordinate;
When attempting to call the Geolocator
object’s GetGeopositionAsync
method, if location is disabled in the phone’s settings, an UnauthorizedAccessException
is raised.
Note
The Coordinate property of the Geoposition
class is of type Windows.Devices.Geolocation.Geocoordinate
, which is not to be confused with the System.Device.Location.GeoCoordinate
class. Notice the capital “C” in the latter type name.
Other types, such as the Geoposition
class, use the same casing pattern to indicate that they belong to the WinPRT API and not the .NET API.
The .NET GeoCoordinate type (and not the WinPRT Geocoordinate type) is used heavily by the phone’s mapping API, which is explored in the next chapter. Converting between the two types is a matter of copying over the various property values. Listing 17.1 shows an extension method that is used to convert a WinPRT Geocoordinate
into a .NET GeoCoordinate
.
static class GeocoordinateExtensions
{
public static GeoCoordinate ToGeoCoordinate(this Geocoordinate geocoordinate)
{
return new GeoCoordinate
(
geocoordinate.Latitude,
geocoordinate.Longitude,
geocoordinate.Altitude ?? Double.NaN,
geocoordinate.Accuracy,
geocoordinate.AltitudeAccuracy ?? Double.NaN,
geocoordinate.Speed ?? Double.NaN,
geocoordinate.Heading ?? Double.NaN);
}
}
The Geoposition
result of the GetGeopositionAsync
method potentially represents a cached reading. Caching the reading saves the geo location infrastructure from having to engage hardware components. GetGeopositionAsync
has a method overload that allows you to specify the maximum age of the cached reading and the maximum number of seconds that the OS should wait to get a location result before timing out and raising an exception.
It is recommended that you use the GetGeopositionAsync
method when tracking is not required because it results in better battery life and, therefore, a better user experience.
Geolocator
allows you to request a desired accuracy level via its DesiredAccuracy
property, which can be set to either the default accuracy level, which lets the OS decide the accuracy level, or a high accuracy level, which causes the OS to prefer the accuracy of GPS. To create a Geolocator
that uses the default accuracy setting, use the following:
Geolocator defaultAccuracyLocator = new Geolocator();
For high accuracy, set the DesiredAccuracy
property like so:
Geolocator highAccuracyLocator
= new Geolocator {DesiredAccuracy = PositionAccuracy.High};
The PositionAccuracy
enum has the following two values:
Default—Results in a power optimized (or low power) configuration at the probable cost of decreased accuracy. Moreover, the phone device favors the use of cell tower triangulation and Wi-Fi triangulation above GPS.
High—Favors GPS when available at the cost of greater power usage and, thus, reduced battery life.
Best Practices
Use the default (power optimized) accuracy setting unless a higher level of accuracy is required. Using lower accuracy minimizes power consumption, thereby increasing battery life.
In addition to the DesiredAccuracy
property, Geolocator
includes a DesiredAccuracyInMeters
property, which is not present in the older GeoCoordinateWatcher
API. The DesiredAccuracyInMeters
property is a nullable unsigned integer value that lets the OS choose the mechanism for geo location. Lower values cause the phone to prefer the accuracy of GPS.
Setting the DesiredAccuracyInMeters
property to a non-null value overrides the DesiredAccuracy
property.
In some environments, signal noise can cause a GPS device to register movement when there is no movement. This can be caused by surface reflection, which occurs when signals bounce off walls or other structures, or by other environmental factors. It is also exacerbated by the absence of a GPS antenna on Windows Phone devices.
The MovementThreshold
property of the Geolocator
allows you to specify the minimum amount of movement required to register a change in position. When a change is registered, the Geolocator
’s PositionChanged
event is raised.
MovementThreshold
is a double
value, which indicates the distance in meters, relative to the last coordinate received. The MovementThreshold
property allows position change notifications to be smoothed. If the value is set too low, the PositionChanged
event may be raised too frequently, or when there is no actual change in location. Conversely, setting the value too high reduces the ability of the device to provide up-to-date location coordinates. A road navigation app, for example, with a MovementThreshold
value set too high, may cause a user to miss a turn. Set too low, the application may provide continuous directions when the phone is, in fact, stationary.
Tip
Setting the Geolocator.MovementThreshold
property to at least 20 helps to smooth out the signal, causing the PositionChanged
event to be raised only when the location has changed significantly.
The Geolocator
class exposes the following two events:
PositionChanged—This event is raised when a change in location is detected.
StatusChanged—This event is raised when the underlying location service changes state; for example, when the location component is receiving data or when it has been disabled.
The PositionChanged
event is raised whenever a significant change is detected in the phone’s location. How large the change needs to be is determined by the Geolocator
object’s MovementThreshold
property.
The following code fragment demonstrates how to subscribe to the PositionChanged
event:
geolocator.PositionChanged += HandlePositionChanged;
When the PositionChanged
event is raised, the handler receives a PositionChangedEventArgs
object that contains a Geoposition
property, as shown:
void HandlePositionChanged(
Geolocator sender, PositionChangedEventArgs e)
{
Geoposition geoposition = e.Position;
Geocoordinate geocoordinate = geoposition.Coordinate;
CivicAddress civicAddress = geoposition.CivicAddress;
}
The Position
property of the PositionChangedEventArgs
is a Geoposition
instance containing the following two properties:
Coordinate
(of type Geocoordinate
)
CivicAddress
(of type CivicAddress
In the context of the geo location API, a position can be thought of as a location at a point in time. Geocoordinate
includes a Timestamp
property of type DateTimeOffset
, which indicates when the reading was taken.
Best Practices
Geolocator
leverages phone hardware that consumes power. Subscribe to its PositionChanged
event only when it is needed by your app, and unsubscribe as soon as it is no longer needed. This reduces power consumption and increases the battery life of the phone.
The status of the underlying geographic location component is indicated by the Geolocator
object’s LocationStatus
property, which is of type PositionStatus
. PositionStatus
is an enum that contains the following values:
Disabled—The location provider is disabled. No position updates occur.
Initializing—The location provider is initializing. This status occurs, for example, when the GPS component is obtaining a fix.
NoData—No location data is available from any location provider.
NotAvailable—The Windows Sensor and Location Platform is not available on the device. The minimum Windows Phone hardware requirements preclude this status.
NotInitialized—An operation to retrieve location has not yet been initialized. LocationStatus
will have this value if the application has not yet called GetGeopositionAsync
or registered an event handler for the PositionChanged
event.
Ready—A location provider is ready to supply new data. In this state, the Geolocator
is able to raise its PositionChanged
event.
The location provider transitions between these states, as depicted in Figure 17.4.
When the Geolocator
object’s StatusChanged
event is raised, the handler receives a StatusChangedEventArgs
object, as shown in the following excerpt:
void HandleStatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
PositionStatus status = args.Status;
switch (status)
{
case PositionStatus.Disabled:
// ...
break;
case PositionStatus.Initializing:
// ...
break;
case PositionStatus.NoData:
// ...
break;
case PositionStatus.NotInitialized:
// ...
break;
case PositionStatus.Ready:
// ...
break;
}
}
3.144.48.3