This is part 2 of a series of 4 blog posts covering Location and the ArcGIS Runtime SDKs. In part 1 we introduced the AGSLocationDisplay which is responsible for working with the AGSMapView to give your app a "blue dot" experience, and we talked about customizing the behavior and appearance of the current location on your map.
In this post, we'll talk about the third component of AGSLocationDisplay, which is where that location information comes from: the location data source…
Location Data Sources
A location data source feeds location updates to the AGSLocationDisplay which in turn takes care of updating the map view according to the configuration options discussed in part 1.
It is accessed via the AGSLocationDisplay.dataSource property.
The ArcGIS Runtime SDK for iOS comes with a few location data sources out of the box:
|Data Source Type||Purpose|
|AGSCLLocationDataSource||Follow your iOS device's built-in Core Location services (the default).|
|AGSSimulatedLocationDataSource||Follow a sequence of simulated locations or an AGSPolyline.|
|AGSGPXLocationDataSource||Follow the contents of a GPX file.|
Each of these location data sources inherits from the base AGSLocationDataSource class:
By default an AGSLocationDisplay automatically creates and uses an AGSCLLocationDataSource. Just call AGSMapView.locationDisplay.start(completion) to start showing your location (but see the note here about configuring your app according to Apple's requirements for enabling location).
Custom Location Data Sources
What's neat is that by inheriting from AGSLocationDataSource and implementing a few simple methods, you can create your own custom data source that Runtime integrates with in exactly the same way as the 3 out-of-the-box ones mentioned above (which are themselves built using the pattern we'll discuss).
This extensibility is very powerful if you're working with proprietary location technology, such as an external high-accuracy GPS unit, a beacon-based indoor location system, or some other location determining system whose manufacturers provide an API or SDK.
Step-by-step, here's how you build out your own custom AGSLocationDataSource:
- Inherit from AGSLocationDataSource.
- Implement doStart().
- Called by Runtime when the app calls AGSLocationDisplay.start(completion).
- This must call didStartOrFailWithError() to signal that your source started OK (or failed to start).
When you call didStartOrFailWithError() you either pass in nil if your source started OK and is ready to start providing locations, or pass in an Error if it failed to start.
- Implement doStop().
- Called by Runtime when the app calls AGSLocationDisplay.stop().
- This must call didStop() to signal that your source stopped OK.
That takes care of starting and stopping the data source when instructed to, but you also need to notify Runtime when you get new locations:
- Call didUpdate(location) whenever you get a new location you need to pass on. You construct an AGSLocation object and call didUpdate(), passing in that location.
An AGSLocation combines an AGSPoint with a timestamp. It also includes velocity, heading, accuracy estimates, and whether this location should be considered current or is an old (or "last known") location. Some of these properties are used to determine how the location is displayed in the map view.
That's it. With that implemented, you have a functioning Location Data Source. Let's discuss the documentation available to us about this, and how it all fits together.
Understanding Location Data Sources
First, let's look at the AGSLocationDataSource (ForSubclassEyesOnly) API, described in the reference docs:
These methods determine how your custom location data source and the AGSLocationDisplay will communicate.
A note on naming:
- do… Instructions from the AGSLocationDisplay to your custom AGSLocationDataSource begin with "do" (doStart() and doStop()). These indicate an imperative from the location display for your data source to do something.
- did… Feedback from your data source to the AGSLocationDisplay is done by calling functions that begin with "did" (didUpdateLocation(), didStartOrFailWithError(), didStop() etc.). These indicate feedback from your data source to update the location display (e.g. the state changed, or a new location is available).
The "do" methods are expected to exist in your subclass of AGSLocationDataSource, so it's up to you to implement them.
The 'did' methods are all inherited from AGSLocationDataSource, so they're already defined for use by your subclass. You don't implement them. You just call them directly.
Here's how these methods work together:
- When an app wants to show location updates (by calling AGSMapView.locationDisplay.start(completion)), the AGSLocationDisplay will call doStart() on its dataSource.
- The data source initializes itself and calls didStartOrFailWithError(nil) to show it's started OK. It starts providing location updates by calling didUpdate(location) for each location update.
- When the app wants to stop showing location, it calls AGSMapView.locationDisplay.stop() and the AGSLocationDisplay will call doStop() on its dataSource. The data source calls didStop() and makes sure it doesn't call didUpdate(location) any more.
That's it for the theory. In the next blog post, we'll look at creating a custom AGSLocationDataSource from scratch and show it in use in a simple iOS application.