page.title=Google Map View
parent.title=Hello, Views
parent.link=index.html
@jd:body

<p>Using the Google Maps library, you can create your own map-viewing Activity. In this
tutorial, you'll create a simple map application in two parts. In Part 1, you'll create an app that
shows a map the user can pan and zoom. In Part 2, you'll add overlay items that mark
points of interest.</p>

<div class="special">
<p>This tutorial requires that you have the external Google Maps library
installed in your SDK environment. The Maps library is included with the Google APIs
add-on, which you can install using the Android SDK and
AVD Manager. To learn how, see <a href="{@docRoot}sdk/adding-components.html">Adding SDK
Components</a>.</p>

<p>After installing the Google APIs add-on in your SDK, set your project properties to use the build
target called "Google APIs by Google Inc.". See the instructions for setting a build
target in <a href="{@docRoot}guide/developing/eclipse-adt.html">Developing in
Eclipse with ADT</a> or <a
href="{@docRoot}guide/developing/other-ide.html">Developing in Other IDEs</a>,
as appropriate for your environment. </p>

<p>You will also need to set up a new AVD that uses the same Google APIs deployment target. See <a
href="{@docRoot}guide/developing/tools/avd.html">Android Virtual Devices</a> for
more information.</p>

<p>For reference material, see the <a
href="http://code.google.com/android/add-ons/google-apis/reference/index.html">Google Maps
library documentation</a>.</p>

</div>

<h2>Part 1: Creating a Map Activity</h2>

<ol>
  <li>Start a new project named <em>HelloGoogleMaps</em>.</li>

  <li>Because the Maps library is not a part of the standard Android library, you must
  declare it in the Android Manifest. Open the <code>AndroidManifest.xml</code>
  file and add the following as a child of the <code>&lt;application></code> element:
  <pre>&lt;uses-library android:name="com.google.android.maps" /></pre>
  </li>

  <li>You also need access to the Internet in order to retrieve map tiles,
  so you must also request the {@link android.Manifest.permission#INTERNET} permission.
  In the manifest file, add the following as a child of the <code>&lt;manifest></code> element:
  <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
  </li>

  <li>While you're in the manifest, give the map some more space by getting rid of the title bar
with the "NoTitleBar" theme:
<pre>
&lt;activity android:name=".HelloGoogleMaps" android:label="@string/app_name"
     <strong>android:theme="@android:style/Theme.NoTitleBar"</strong>&gt;
</pre>
  </li>


  <li>Open the <code>res/layout/main.xml</code> file and add a single
  {@code com.google.android.maps.MapView} as the root node:
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;com.google.android.maps.MapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mapview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true"
    android:apiKey="<em>Your Maps API Key goes here</em>"
/>
</pre>
    <p>The <code>android:clickable</code> attribute defines whether you want to allow
    user-interaction with the map. If this is "false" then touching the map does nothing.</p>

    <p>The <code>android:apiKey</code> attribute holds the Maps API Key for your
    application, which proves your application and signer certificate has been registered with the
    Maps service. This is required in order to receive the map data, even while you are
    developing. Registration to the service is free and it only takes a couple
    minutes to register your certificate and get a Maps API Key.</p>
    <p>Go now to get a key. For instructions, read
    <a href="http://code.google.com/android/add-ons/google-apis/mapkey.html">Obtaining a Maps API
    Key</a>. For the purpose of this tutorial, you should <a
  href="http://code.google.com/android/add-ons/google-apis/mapkey.html#getdebugfingerprint">register
    with the SDK debug certificate</a>, which will only be valid while your application is signed
    with the debug key (once you sign with your private key, you will need a new API key).
    When you get your key, insert it for the value of <code>android:apiKey</code>.</p>
  </li>

  <li>Now open the <code>HelloGoogleMaps.java</code> file. For this Activity, extend
  {@code MapActivity} (instead of {@code android.app.Activity}):</p>

    <pre>public class HelloGoogleMaps extends MapActivity {</pre>
    <p>This is a special sub-class of {@link android.app.Activity}, provided by the Maps
    library, which provides important map capabilities.</p>

   <li>Inside every {@code MapActivity}, the <code>isRouteDisplayed()</code> method is required, so
    override this method:
<pre>
&#64;Override
protected boolean isRouteDisplayed() {
    return false;
}
</pre>
<p>This method is required for some accounting from the Maps service to see if you're currently
displaying any route information. In this case, you're not, so return false.</p>
</li>

<li>Now add the standard {@link android.app.Activity#onCreate(Bundle) onCreate()} callback method
to the class:
<pre>
&#64;Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}
</pre>
<p>This loads the layout file created above. In fact, this is now a workable application that will
display map tiles and allow the user to pan around the map. But there's no ability to zoom.
Fortunately, there's a very simple zoom feature built into the {@code MapView} class, which you can
summon with {@code setBuiltInZoomControls(boolean)}. Do this at the end of the {@link
android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
<pre>
    MapView mapView = (MapView) findViewById(R.id.mapview);
    mapView.setBuiltInZoomControls(true);
</pre>
</li>
<li>That's all there is to it. Run the application. (Remember, you must have an <a
href="{@docRoot}guide/developing/tools/avd.html">AVD</a> configured to use the Google APIs
target, or be using a development device that includes the Maps library.)</li>
</ol>

<h2>Part 2: Adding Overlay Items</h2>

<p>So, now you have a map, but in many cases you'll also want to create your own map
markers and lay-overs. That's what you'll do now. In order to do so, you must implement the
{@code ItemizedOverlay} class, which can manage a whole set of {@code Overlay} (which are the
individual items placed on the map).</p>

<ol>   
  <li>Create a new Java class named <code>HelloItemizedOverlay</code> that implements
  {@code ItemizedOverlay}.

    <p>When using Eclipse, right-click the package name in the Eclipse Package Explorer, and
    select <strong>New > Class</strong>. Fill-in
    the Name field as <em>HelloItemizedOverlay</em>. For the Superclass, enter
    "com.google.android.maps.ItemizedOverlay". Click the checkbox for <em>Constructors from
    superclass</em>. Click Finish.</p></li>

  <li>First, you need an <code>OverlayItem</code> {@link java.util.ArrayList}, in which you'll put
  each of the <code>OverlayItem</code> objects you want on the map. Add this at the top of the
  <code>HelloItemizedOverlay</code> class:

      <pre>private ArrayList&lt;OverlayItem> mOverlays = new ArrayList&lt;OverlayItem>();</pre>
  </li>

  <li>Now define the <code>HelloItemizedOverlay</code> constructors. The constructor must
  define the default marker for each of the {@code OverlayItem}s. In order for the {@link
  android.graphics.drawable.Drawable} to actually get drawn, it must have its bounds  defined. Most
  commonly, you want the center-point at the bottom of the image to be the point at which it's
  attached to the map coordinates. This is handled for  you with the {@code boundCenterBottom()}
  method. Wrap this  around our defaultMarker, so the super  constructor call looks like this:
<pre>
public HelloItemizedOverlay(Drawable defaultMarker) {
  super(boundCenterBottom(defaultMarker));
}
</pre>
  </li>

  <li>In order to add new {@code OverlayItem}s to the ArrayList, you need a new method:
<pre>
public void addOverlay(OverlayItem overlay) {
    mOverlays.add(overlay);
    populate();
}</pre>
    <p>Each time you add a new {@code OverlayItem} to the ArrayList, you must call
    <code>populate()</code> for the {@code ItemizedOverlay}, which will read each of the
    {@code OverlayItem}s and prepare them to be drawn.</p>
  </li>

  <li>When the <code>populate()</code> method executes, it will call <code>createItem(int)</code> in
  the {@code ItemizedOverlay} to retrieve each {@code OverlayItem}. You must override this method to
  properly read from the ArrayList and return the {@code OverlayItem} from the position specified
  by the given integer. Your override method should look like this:

<pre>
&#64;Override
protected OverlayItem createItem(int i) {
  return mOverlays.get(i);
}
</pre>
  </li>

  <li>You must also override the <code>size()</code> method to return the current number of
  items in the ArrayList:
<pre>
&#64;Override
public int size() {
  return mOverlays.size();
}
</pre>
  </li>

  <li>Now set up the ability to handle touch events on the overlay items. First, you're
  going to need a reference to the application {@link android.content.Context} as a member of
  this class. So add {@code Context mContext} as a class member, then initialize it with a
  new class constructor:
<pre>
public HelloItemizedOverlay(Drawable defaultMarker, Context context) {
  super(defaultMarker);
  mContext = context;
}
</pre>
    <p>This passes the {@code defaultMarker} up to the default constructor to bound its coordinates
    and then initialize {@code mContext} with the given {@link android.content.Context}.</p>

    <p>Then override the {@code onTap(int)} callback method, which will handle the event
    when an item is tapped by the user:</p>
<pre>
&#64;Override
protected boolean onTap(int index) {
  OverlayItem item = mOverlays.get(index);
  AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
  dialog.setTitle(item.getTitle());
  dialog.setMessage(item.getSnippet())
  dialog.show();
  return true;
}
</pre>
    <p>This uses the member {@code android.content.Context} to create a new {@link
android.app.AlertDialog.Builder} and uses the tapped {@code OverlayItem}'s title and snippet for
the dialog's title and message text. (You'll see the {@code OverlayItem} title and snippet defined
when you create it below.)</p>
  </li>

</ol>

<p>You're now done with the <code>HelloItemizedOverlay</code> class and can start using it
to add items on the map.</p>

<p>Go back to the <code>HelloGoogleMaps</code> class. In the following procedure, you'll create an
{@code OverlayItem} and add it to an instance of the <code>HelloItemizedOverlay</code> class, then
add the <code>HelloItemizedOverlay</code> to the <code>MapView</code> using a {@code GeoPoint}
to define its coordinates on the map.</p>

<img src="images/androidmarker.png" align="right" />
<ol>
  <li>First, you need the image for the map overlay. If you don't have one handy, use the Android on
  the right. Drag this image (or your own) into the <code>res/drawable/</code> directory of your
  project.</li>

  <li>At the end of your existing {@code onCreate()} method, instantiate :

<pre>
List&lt;Overlay> mapOverlays = mapView.getOverlays();
Drawable drawable = this.getResources().getDrawable(R.drawable.androidmarker);
HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(drawable);</pre>

    <p>All overlay elements on a map are held by the {@code MapView}, so when you want to add some,
    you have to get a list from the <code>getOverlays()</code> method. Then instantiate the {@link
    android.graphics.drawable.Drawable} used for the map marker, which was saved in the {@code
    res/drawable/} directory. The constructor for {@code HelloItemizedOverlay} (your custom {@code
    ItemizedOverlay}) takes the Drawable in order to set the default marker for all overlay
    items.</p>
  </li>

  <li>Now create a {@code GeoPoint} that defines the map coordinates for the first overlay item,
  and pass it to a new {@code OverlayItem}:
<pre>
GeoPoint point = new GeoPoint(19240000,-99120000);
OverlayItem overlayitem = new OverlayItem(point, "Hola, Mundo!", "I'm in Mexico City!");
</pre>

    <p>{@code GeoPoint} coordinates are specified in microdegrees (<code>degrees * 1e6</code>). The
    {@code OverlayItem} constructor accepts the {@code GeoPoint} location, a string for the
    item's title, and a string for the item's snippet text, respectively.</p>
  </li>

  <li>All that's left is to add this {@code OverlayItem} to your collection in the
  {@code HelloItemizedOverlay} instance, then add the {@code HelloItemizedOverlay} to the MapView:
<pre>
itemizedoverlay.addOverlay(overlayitem);
mapOverlays.add(itemizedoverlay);
</pre>
  </li>

  <li>Now run the application.</li>
</ol>

<p>You should see the following:</p>
<img src="images/hello-mapview.png" width="150px" />
<p>When you tap the overlay item, you'll see the dialog appear.</p>

<p>Because the {@code ItemizedOverlay} class uses an {@code java.util.ArrayList} for all of the
{@code OverlayItem}s, it's easy to add more. Try adding another one. Before the
<code>addOverlay()</code> method is called, add these lines:</p>
<pre>
GeoPoint point2 = new GeoPoint(35410000, 139460000);
OverlayItem overlayitem2 = new OverlayItem(point2, "Sekai, konichiwa!", "I'm in Japan!");
</pre>
<p>Run the application again. (You probably need to move the map to find the new overlay item.)</p>

