By Monica Tran, Google Maps API Team
Cross-posted from the Google
Geo Developers Blog
In this post, we hear from Monika Szymanski and Mike Kelley of the Orbitz Android
engineering team, who recently migrated from version 1 to version 2 of the Google
Maps Android API.
About Orbitz
Nearly 30% of Orbitz.com hotel bookings are now made via mobile devices, fueled in part by the
growth of the Android platform. The recently released 3rd-generation update of the
Orbitz - Flights, Hotels,
Cars app for Android brings major speed and ease of use improvements along with the
latest Android UI design patterns to the app. The
Google
Maps Android API v2 is also integrated into the hotel search experience.
Read on to find out how we did it, with tips and sample code along the way.
Migrating from v1 to v2 of
the Google Maps Android API
While users of the Orbitz.com Android app will notice some changes to the app’s user interface
for maps, the changes to our code are more than skin deep. New classes offered in v2 of the
Google Maps Android API like
MapFragment
and
SupportMapFragment,
the transition from ItemizedOverlays to
Markers,
and the addition of a well-supported info window pattern have made including a Google Map in
an Android app much easier.
|
Say hello to the 3rd
generation of Orbitz - Flights, Hotels, Cars app, using the Google Maps Android API
v2 |
Featuring Fragments
Prior to the introduction of
MapFragment (and
SupportMapFragment)
in v2, we had to write a lot of code to manually show/hide the map view in our app. Only one
instance of MapView could be created per activity, so we had to be overly clever about
persisting that instance in our Activity. Lack of proper Fragment support was a common
pain point for
developers integrating v1 of the Google Maps Android API in their application.
When Fragment support was added in v2, we essentially rewrote our map code to take advantage
of the new features of MapFragment. Let’s start by taking a look at our hotel results Activity
layout:
You’ll notice that we’re not including the actual
fragment in the layout - we add the fragment at runtime, because we don’t want to pay the cost
of the fragment transaction and add all the markers on the map, unless the user requests
it.
You’ll also notice a bit of a hack at the bottom of the layout. In testing, we found that the
MapFragment would leave a black box artifact on the screen on certain devices when the user
opened our sliding menu navigation. Adding a simple FrameLayout “above” the map seems to fix
the problem.
Extending
SupportMapFragment makes
it much easier to separate the map display logic from our Activity and list fragment. Our
SupportMapFragment (and its inner classes) is responsible for:
- Adding markers representing each available hotel
- Customizing the GoogleMap UI options
- Centering and animating the map to show the added markers
- Showing an info window when a marker is clicked
- Launching an Intent to display more details when an info window is
clicked
Next up, we’ll talk about how we add markers to the map and keep memory usage
down.
Managing Markers
One of the challenges in migrating from v1 to v2 of the Google Maps Android API was figuring
out the best way to know which hotel’s info to display when a marker is tapped. To solve this,
we place each <Marker, Hotel> pair in a HashMap when adding the markers to the
Google Map. Later, we can use this HashMap to look up a marker's corresponding hotel
info.
The code snippets below illustrate how we do it.
This HashMap allows us to look up the selected hotel in our InfoWindowAdapter,
enabling us to display more information about it.
We place quite a few markers on the map for hotel results and each marker can have
a different custom image. It's really easy to run out of memory and we were getting quite a
few OutOfMemoryExceptions early in development. To manage memory more effectively, we made
sure we didn't create a new new Bitmap and BitmapDescriptor for every marker placed on the
map. We also ensured that the resources were recycled after we were done with
them.
When the user taps a marker, we want to show more information; that’s where info
windows come in handy.
Introducing Info Windows
Aside from simply viewing the location of all available hotels on a map, users are
typically interested in the name and price of the hotel. The architecture for implementing
this information window changed considerably from version 1 to version 2 of the Google Maps
Android API.
|
Before: Info windows in the Google Maps Android API
v1
|
When using v1 of the Google
Maps Android API, our app displayed more detailed hotel information in a custom info view when
the user tapped on a hotel marker. That custom view displayed the hotel name and price, and
triggered a custom animation when the view was added to the screen. This animation made it
appear that the view was growing from inside the pin on the map.
We achieved this effect by setting the LayoutParams to
MapView.LayoutParams.BOTTOM_CENTER and MapView.LayoutParams.MODE_MAP, which centered the
bottom of the custom view on top of the tapped hotel marker.
With the introduction of the Google Maps Android API v2,
MapView.LayoutParams.MODE_MAP was removed, so we explored alternative treatments to show the
hotel information when the user clicks on a result. For our purposes, the best alternative was
to use the new info window interface.
|
After: Info windows in the
Google Maps Android API v2 |
Creating an
InfoWindowAdapter
is pretty straightforward. The API provides two ways to populate the info window; either by
supplying the contents of the info window (shown in the default window stylec) or creating a
full View. Because we wanted to have a custom window background, loaded from a 9-patch, we
opted to build a complete View for the info window by overriding the getInfoContents() method
to return null, and by returning a custom View from
getInfoWindow().
Here’s a sample of our code:
We could further simplify this code by having our HotelView take a Hotel model as a
parameter in the constructor.
A caveat with info windows is that even though they are populated by
the returned View, the info window is not treated like a *live* View object. The system will
call the view’s draw() method only once, then use that cached rendering as the user continues
to interact with the map. Our existing animation didn’t work in the Google Maps Android API
v2, but we decided to be consistent with the platform and remove the animation rather than try
to hack around this limitation.
We <3 Google Maps Android API
v2
Upgrading from version 1 to version 2 of the Google Maps Android API was virtually
painless and fun to do! The introduction of MapFragment helped us separate the map display
logic from the rest of the code and made code reuse much easier. Using custom info views was
very straightforward with the new info window interface. We look forward to adding even more
Google Map features to our app.
Monika Szymanski is a Lead Engineer on the Android team at Orbitz, where she works
on apps that are friendly, fast, and easy to use. In her free time, she enjoys outdoors,
running, red wine, and anything chocolate.
Mike Kelley is a Software Engineer at Orbitz, where he works on Android travel tools
to help people travel smarter. He's a Michigan grad, transportation and technology enthusiast
and craft beer buff. Some of Mike's ideas and projects live online at theelfismike.com.
Monica Tran joins us from our Google Maps API team in Sydney, where she helps
developers tell stories and build businesses with maps.
Orbitz Worldwide (NYSE: OWW) is a leading global online travel company that uses
innovative technology to enable leisure and business travelers to search for, plan and book a
broad range of travel products and services including airline tickets, hotels, car rentals,
cruises, and vacation packages.
Posted by Scott Knaster,
Editor