Obtaining location coordinates and addresses

Many devices have the ability for us to obtain the location of the user in a very precise manner. Android provides a few means to access the location, including using the network or using Global Positioning System (GPS).

How to do it...

If we are designing an app that requires the user's location, such as finding things nearby, we can use LocationManager to get the user's current location:

  1. If we are only interested in using the network provider, we only need to ask for permission to use coarse location:
    [assembly: UsesPermission(
      Manifest.Permission.AccessCoarseLocation)]
  2. If we want to use GPS, we need to use the fine location permission instead:
    [assembly: UsesPermission(
      Manifest.Permission.AccessFineLocation)]
  3. Once we have permission for location requests, we need to get LocationManager:
    manager = LocationManager.FromContext(this);
  4. We can check to see whether a specific provider, such as GPS, is enabled:
    manager.IsProviderEnabled(
      LocationManager.GpsProvider);
  5. We can also take the user to the settings in order to enable the location services:
    var intent = new Intent(
      Settings.ActionLocationSourceSettings);
    StartActivity(intent);
  6. Before we start requesting new locations, we can use the cached location:
    var cached = manager.GetLastKnownLocation(
      LocationManager.GpsProvider);
  7. We need to provide a destination for the location results when requesting the location, so we implement the ILocationListener interface:
    public class MainActivity : Activity, ILocationListener
    {
      public void OnLocationChanged(Location location)
      {
      }
      public void OnProviderDisabled(string provider)
      {
      }
      public void OnProviderEnabled(string provider)
      {
      }
      public void OnStatusChanged(
        string provider, 
        Availability availability, 
        Bundle extras)
      {
      }
    }
  8. Once we receive a location, the OnLocationChanged method will be invoked and we can access the various location properties:
    double latitude = location.Latitude;
    double longitude = location.Longitude;
  9. Once we have implemented the interface, we can start requesting updates. If our app only requires a single location request, such as to just get a one-off location, we can use the RequestSingleUpdate method:
    manager.RequestSingleUpdate(
      LocationManager.GpsProvider, this, null);
  10. We can also register for a continuous stream of updates using the RequestLocationUpdates method:
    manager.RequestLocationUpdates(
      LocationManager.GpsProvider, 0, 0, this);
  11. We can also request to get updates from multiple providers at the same time:
    manager.RequestLocationUpdates(
      LocationManager.NetworkProvider, 0, 0, this);
  12. We can then find the best location provider to use:
    var criteria = new Criteria();
    var provider = manager.GetBestProvider(criteria, false);
  13. No matter how we register for updates, we can stop listening as well:
    manager.RemoveUpdates(this);

We can also work backwards. If we have location coordinates, we can request information about what is at that location using the Geocoder instance:

  1. Before we start making requests, we need to be sure that Geocoder is available on the device:
    var isPresent = Geocoder.IsPresent;
  2. If Geocoder is available, we can make a request based on latitude, longitude, and the number of results that we want by using the GetFromLocationAsync() method:
    var geocoder = new Geocoder(this);
    var resultCount = 1;
    var addresses = await geocoder.GetFromLocationAsync(
      currentLocation.Latitude, 
      currentLocation.Longitude, 
      resultCount);
  3. This method returns a collection of Address objects that represent places at the given coordinates:
    Address address = addresses.FirstOrDefault();
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < address.MaxAddressLineIndex; i++) {
      var line = address.GetAddressLine(i);
      if (!string.IsNullOrWhiteSpace(line))
        builder.AppendLine(line);
    }
    string addressLines = builder.ToString();
  4. As well as requesting the address lines, we can obtain various bits of information directly:
    string houseNumber = address.SubThroughfare;
    string roadName = address.Throughfare;
    string suburb = address.SubLocality;
    string city = address.Locality;

How it works...

LocationManager provides a uniform way to access a device's physical location from various providers such as cell towers, Wi-Fi, GPS data from other apps and services, and the GPS device itself. Different providers provide varying degrees of accuracy as well as differing power requirements.

GPS is the most accurate but also requires the most power. The network provider, which uses the cell towers and Wi-Fi, is less accurate but requires less power. Less accurate providers can be used if the app does not require a constant stream of updates or needs to consume minimal battery.

In order to access the location services, we need to ask for permission. There are two levels of permissions, fine and coarse. Fine location permission is required for the GPS provider and the passive provider, which uses GPS data collected by other apps. Coarse location permission is used when using the cellular and Wi-Fi location data.

Before requesting location data, we need to be sure that the provider is available and is enabled. We can request that the user enable certain providers if it is needed. Enabling location services can be achieved by showing the settings activity.

When listening for location data, we subscribe to the updates with an interface. In order to catch the updates, we implement the OnLocationChanged() method. This method will be invoked each time there is a new location from one of the location providers. The Location parameter contains several properties which we can use to determine the coordinates and many other location attributes as well as the accuracy and time of the particular result.

We can request updates in two ways: as a single response or as a continuous stream of new location updates. If our app only requires the location once-off or infrequently, we can use the RequestSingleUpdate() method. This will only request a single location result. If we need a stream of updates, we use the RequestLocationUpdates() method.

Both methods require a provider to use when requesting updates. We can request updates from multiple providers using the same receiver as each new location will contain details on where the update came from.

If we are requesting a single update, we supply the provider, the callback, and the thread we wish to invoke the callback on. If we want to use the current thread, we pass null. Similarly, when requesting a stream of updates, we provide the same parameters, but with an additional two. The first additional parameter specifies how frequently, in milliseconds, to request a new update; passing a zero will return them as fast as possible. The second specifies how far, in meters, the device needs to have moved before updating the location.

If we want to find out what provider is the best available, we can pass an instance of Criteria to the GetBestProvider() method. This method tries to find the best provider that matches the given criteria, excluding those that the app does not have permission for. We can also specify what the criteria are for selecting a provider using the various properties on the Criteria type. Some of these properties include Accuracy and Power as well as AltitudeRequired and SpeedRequired.

Once we have the location we need or want to cancel updates, we can use the RemoveUpdates method to stop listening on a particular ILocationListener instance.

We can get an accurate location from the sensors, but sometimes we need to get some idea of what addresses are at or near that location. To do this, we use Geocoder.

Geocoder can provide a collection of Address types that represent the physical addresses that are found near the provided location. There are two ways which we can request addresses: by specific location coordinates using the GetFromLocationAsync() method or by a string location name using GetFromLocationNameAsync().

There's more...

Android provides an additional location provider through Google Play Services: Fused Location Provider is an optional alternative to the standard Android Location Service that automatically handles changes in provider status inside our app. It selects the best provider at any given moment. It also provides the ability to create location-aware apps that use geo-fencing.

More information on using Fused Location Provider can be found at: http://developer.xamarin.com/guides/android/platform_features/maps_and_location/location/.

We can also embed a map directly into our app. This can be used to provide a visual representation of the device's location as well as enable us to place markers on the map showing the locations of various objects.

More information on including maps in an app can be found at: http://developer.xamarin.com/guides/android/platform_features/maps_and_location/maps/part_2_-_maps_api.

One of the requirements for using an embedded map is that we need a Google Maps API key. More information on how to obtain one for our app can be found at: http://developer.xamarin.com/guides/android/platform_features/maps_and_location/maps/obtaining_a_google_maps_api_key/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.16.254