If you are considering Google Maps, please review these terms closely to determine if your intended use will not run afoul of any clauses. You are strongly recommended to seek professional legal counsel if there are any potential areas of conflict.
Also, keep your eyes peeled for other mapping options, based off of other sources of map data, such as OpenStreetMap.[32]
The Bare Bones
Far and away the simplest way to get a map into your application is to create your own subclass of MapActivity
. Like ListActivity
, which wraps up some of the smarts behind having an activity dominated by a ListView
, MapActivity
handles some of the nuances of setting up an activity dominated by a MapView
.
In your layout for the MapActivity
subclass, you need to add an element named, at the time of this writing, com.google.android.maps.MapView
. This is the “longhand” way to spell out the names of widget classes, by including the full package name along with the class name. This is necessary because MapView
is not in the com.google.android.widget
namespace. You can give the MapView
widget whatever android:id
attribute value you want, plus handle all the layout details to have it render properly alongside your other widgets.
However, you do need to have:
• android:apiKey
, which in production will need to be a Google Maps API key — more on this here
• android:clickable="true"
, if you want users to be able to click and pan through your map
For example, from the Maps/NooYawk
sample application, here is the main layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView android:id="@+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:apiKey="<YOUR_API_KEY>"
android:clickable="true" />
<LinearLayout android:id="@+id/zoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" />
</RelativeLayout>
We’ll cover that mysterious zoom LinearLayout
and the apiKey
in later sections of this chapter. In addition, you will need a couple of extra things in your AndroidManifest.xml
file:
• The INTERNET
and ACCESS_COARSE_LOCATION
permissions
• Inside your <application>
, a <uses-library>
element with android:name="com.google.android.maps"
, to indicate you are using one of the optional Android APIs
Here is the AndroidManifest.xml
file for NooYawk:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.commonsware.android.maps">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application android:label="@string/app_name">
<uses-library android:name="com.google.android.maps" />
<activity android:name=".NooYawk" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
That is pretty much all you need for starters, plus to subclass your activity from MapActivity
. If you were to do nothing else, and built that project and tossed it in the emulator, you’d get a nice map of the world. Note, however, that MapActivity
is abstract — you need to implement isRouteDisplayed()
to indicate if you are supplying some sort of driving directions or not.
In theory, the user could pan around the map using the directional pad. However, that’s not terribly useful when the user has the whole world in her hands.
Since a map of the world is not much good by itself, we need to add a few things…
Exercising Your Control
You can find your MapView
widget by findViewById()
, no different than any other widget. The widget itself then offers a getMapController()
method. Between the MapView
and MapController
, you have a fair bit of capability to determine what the map shows and how it behaves. The following sections cover zoom and center, the features you will most likely want to use.
Zoom
The map of the world you start with is rather broad. Usually, people looking at a map on a phone will be expecting something a bit narrower in scope, such as a few city blocks.
You can control the zoom level directly via the setZoom()
method on the MapController
. This takes an integer representing the level of zoom, where 1 is the world view and 21 is the tightest zoom you can get. Each level is a doubling of the effective resolution: 1 has the equator measuring 256 pixels wide, while 21 has the equator measuring 268,435,456 pixels wide. Since the phone’s display probably doesn’t have 268,435,456 pixels in either dimension, the user sees a small map focused on one tiny corner of the globe. A level of 16 will show you several city blocks in each dimension and is probably a reasonable starting point for you to experiment with.
If you wish to allow users to change the zoom level, you will need to do a few things:
• First, pick a spot on the screen where you want the zoom controls to appear. These are not huge, and they only appear when being used, so they can overlay the actual map itself if you choose. In the layout previously shown, for example, the zoom controls are placed over the map, in the lower-left corner of the screen. You should use a LinearLayout
or other simple container for the zoom controls’ position in your layout.
• In your activity’s onCreate()
method, get your zoom controls’ container via findViewById()
.
• Add the result o f map.getZoomControls()
to that container.
For example, here are the lines from the NooYawk
activity’s onCreate()
method that accomplish the latter points:
ViewGroup zoom = (ViewGroup)findViewById(R.id.zoom);
zoom.addView(map.getZoomControls());
Then, you can manually get the zoom controls to appear by calling displayZoomControls()
on your MapView
, or they will automatically appear when the user pans the map as seen in Figure 34-1.