What's right with Google Maps Android V2
TL:DR The new maps are awesome. The API has been cleaned up (with all my previous complaints addressed) and the map itself is stunning. Beautiful. Fast vector maps viewed from arbitary camera positions.
Given my vocal compaints about the shortfalls of the old Android maps library, I would be remiss if I didn't comment on Google's rewrite.
Because maps are encapsulated in the MapFragment class, you can implement them by extending the Android standard Activity class, rather than extending the MapActivity used in version 1.
With this the main issue I had with the old library, the dependancy on the MapActivity, has been fixed. There is now no requirement to extend MapActivity and, my second issue with the old maps, no limitation on the number of MapViews that can be embedded in a single layout. Just to test this I put together a quick demo using a bog standard activity inflating a layout with two fragments:
<fragment
android:id="@+id/map_fragment1"
android:layout_width="match_parent"
android:layout_height="200dip"
class="com.google.android.gms.maps.MapFragment"/>
<fragment
android:layout_below="@+id/map_fragment1"
android:id="@+id/map_fragment2"
android:layout_width="match_parent"
android:layout_height="200dip"
class="com.google.android.gms.maps.MapFragment"/>
This took about ten minutes to set up and worked perfectly. A bit of a departure from my previous attempts to get two of the old MapViews on screen at the same time (also check out the fancy rotation on those maps):
So two of my three issues with maps are fixed. The third was actually pretty minor and in hindsight not such a big deal. There is still the requirement for a maps key which is associated with the signing certificate for your app. Sometimes looking back at a rant you wonder what you were thinking when you wrote it and this was one of those times:
In addition to these architectural improvements, the new maps API provides some pretty neat functional addtions. Maps are rendered using vector data, so smooth, arbitary camera changes are now possible. In addition to rotation and pinch zoom, if you stick a map in your Android app your users will now be able to slide two fingers onscreen to change the camera pitch (seeing markers laid out on a 3D map of sydney for the first time was pretty cool).
As you would expect from a maps API, markers (with info windows) are now fully supported (more on this next), but you can also add polylines and polygons pretty easily.
Adding markers to a map in v1 of the API was shockingly problematic. To illustrate what I mean, to get info window enabled taxi markers moving around on a map in the last version of goCatch I had to build all of this:
- MarkerItemizedOverlay.java - Extending BalloonItemizedOverlay<OverlayItem> to manage the drawables that get used for markers, forwarding select and clear events from the baseclass on to delegates (in this case the map activity).
- BalloonItemizedOverlay.java - Extending ItemizedOverlay<OverlayItem> to show info windows when OverlayItems are tapped and forwarding events down to the MarkerItemizedOverlay. Making sure that tapped items result in map view changes to center that item. Some jiggery-pokery (that's actually a thing) to ensure that only one info window is shown at a time.
- BalloonOverlayView.java - A nice custom view with a nine part background drawable and some info about the selected marker.
- MapViewWrapper.java - Ugh! The old mapview didn't have a nice OnCameraChangeListener so you had to put code in the draw method of a class extending the MapView and constantly check if the zoom or pan had changed.
- PassengerMapActivity.java - Extending MapActivity and managing all the previously described bits and pieces so they reflect the position of the passenger and the current set of taxis on the map.
In these descriptions I am minimizing the amount of hacking involved to get all this to hang together in a reasonably usable way. It really was quite a lot of horrible code (especially MarkerItemizedOverlay and BalloonItemizedOverlay).
Last week I spent a couple of days ripping out all of that stuff and replacing it with code to use the new API and damn it felt good. This is what I have now:
- BalloonInfoWindow.java - Basically BalloonOverlayView. We still need a nice custom view to show when markers get tapped.
- PassengerMapActivity.java - Extends SherlockFragmentActivity (Yep, I can now extend whatever the hell I like and still show a map on screen). Grabs the MapFragment from the FragmentManager, turns on some awesome properties with a UISettings, listens on a variety of interfaces ( OnMarkerClickListener, OnCameraChangeListener, InfoWindowAdapter, OnMyLocationChangeListener, OnMenuItemClickListener) so it can react to map changes and provide a BalloonInfoWindow when someone taps on a marker.
Going through this code again to write this post, it is pretty striking how much an improvement the new API is.
The only hurdle I faced when switching to v2 of Android Maps was the limitation that you couldn't change the icon on a marker after it is created. At goCatch we like our taxi icons to glow when you tap on them, so I needed to jump through some hoops to get this to happen (deleting tapped markers and re-creating them with a new icon). After complaining loudly on the social networks (that's how I roll) I got a response that a feature request had been created to fix this (thanks Chris Broadfoot).
Here are the results of the couple of days I spent refactoring goCatch to use the new maps (also including a brand new Action Bar Sherlock):
My congratulations to the Android Maps team. You have taken a real pain point for Android devs and turned it into an absolute pleasure. I am looking forward to hearing from Android users of goCatch when we ship this new version.
Permalink - Tags: Development,Android