My Map Location Tutorial – Where am I?

If you’re writing an Android App using a MapView, then you will most likely want to view the user’s location.  This tutorial will show you how to create an activity that makes use of Android’s built-in MyLocationOverlay class.

Step 1: Obtain Google Maps API key

So you want to see where you are on a Google MapView in Android?  Well, the first step in this process is to register for a Google maps api-key.  This key will allow your app to integrate Google Map functionality, download tiles , and more.  Visit this site first to get your key: http://code.google.com/android/add-ons/google-apis/mapkey.html

Step 2: Create a new Android project

We will assume you have obtained your Maps API key, so you should make a new Android project.  When selecting the build target, ensure you use the Google libraries version.  These libraries have all the Android libraries, but add additional functionality like the map view elements.

If you haven’t downloaded any Google APIs libraries yet, you need to first do that using the Android package manager Eclipse plugin.

Step 3: Create a layout

If you followed the New Android project Eclipse wizard,  you should have a main.xml in the layout folder.  Let’s change it to add a MapView. Plus, add your Api key you got from Google in step 1 in the layout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<com.google.android.maps.MapView
		android:id="@+id/mapview" android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:clickable="true"
		android:apiKey="[INSERT YOUR API-KEY HERE]" />
</LinearLayout>

Step 4: Create a MapActivity

If you followed the Eclipse wizard to create your Android project, then the default Activity is simply that — an Activity.  You need to change it to MapActivity.  If Eclipse shows an error for that class, then you didn’t select the Google API libraries as your build target in Step 2.

In your onCreate method, you will want to extract the MapView element from your layout, create a MyLocationOverlay class, and add that overlay to your MapView’s overlays.  After that you should your onCreate should look something like this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // main.xml contains a MapView
    setContentView(R.layout.main); 

        // extract MapView from layout
	mapView = (MapView) findViewById(R.id.mapview);
	mapView.setBuiltInZoomControls(true);

	// create an overlay that shows our current location
	myLocationOverlay = new MyLocationOverlay(this, mapView);

	// add this overlay to the MapView and refresh it
	mapView.getOverlays().add(myLocationOverlay);
	mapView.postInvalidate();
}

Step 5: Register for Location Updates

You’ve added the MyLocationOverlay class to your MapView, but it won’t do anything until you register for location updates.  You could put this code in the onCreate method, but there is an opportunity to leak memory if your app is destroyed and you haven’t unregistered for updates.  So we will put the register code in onResume, and *important* put the unregister code in onPause.  This way, you will only receive location updates if you app is active and showing.

The code will look something like this:

    @Override
	protected void onResume() {
		super.onResume();
		// when our activity resumes, we want to register for location updates
		myLocationOverlay.enableMyLocation();
	}

	@Override
	protected void onPause() {
		super.onPause();
		// when our activity pauses, we want to remove listening for location updates
		myLocationOverlay.disableMyLocation();
	}

Step 6: Update your Manifest

If you were to try and run this code now, it would definitely not work.  We need to modify our manifest.xml file to include the Google maps library, and add permissions to access the internet and location services.

Here’s a modified manifest file.  Note: the uses-library section is correctly inside the application tag (a common mistake).

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.joshclemm.android.tutorial"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MyMapLocationActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    <!-- Make sure the uses-library line is inside the application tag -->
	<uses-library android:name="com.google.android.maps" />
    </application>
	<uses-permission android:name="android.permission.INTERNET" />
	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

Step 7: Fix MyLocationOverlay bug

Our current code may well run on your phone, but some phones have a bug in the MyLocationOverlay class (notably Droid X).  So if you’re releasing a MapView app to the public, you will want to ensure your code does not crash on a buggy phone.  (Do a web search for “MyLocationOverlay bug” for more details).

The fix is to create a class that extends MyLocationOverlay and catch the exception on buggy phones.  If caught, you need to override the drawMyLocation method to mimic what the actual code should show.

The source code for this fixed overlay class can be downloaded from the link below.

Step 8: Grab this tutorial’s project source

The full source code for this project can be found here: http://code.google.com/p/android-my-map-location/

  • Pingback: RealTime - Questions: "How can I add my name in google maps?"()

  • Its like you learn my thoughts! You seem to understand a lot about this, like you wrote the ebook in it or something. I believe that you can do with some percent to drive the message home a little bit, however instead of that, this is magnificent blog. A great read. I’ll definitely be back.

  • Aarthi

    Best tutorial on maps in android :) Thanks a lot :)

  • Pingback: My Map Location – Where am I ? « Breakhearts()

  • Suidoken

    Hello,
    Thanks for the tutorial! Helped me a lot. But I still have a question: after downloading the source and changing the changing the key in the main.xml, the warning message “Cannot dertermine location” appears. Do you have an idea why the getMyLocation() method doesn’t output anything?
    Thanks for answering, and go on with your great blog!

  • Suidoken

    Found the answer! When working with the emulator, i had to activate the DDMS view in Eclipse, and then set the location manually, in the Emulator Control Tab.
    http://developer.android.com/guide/developing/debugging/ddms.html

  • David

    Great Tutorial!

    I would like to customize the MyLocation marker to add a TextView that can display a messages. Whats the best way to go about doing this? Should I add a drawable to the Overlay?

    Thanks,

  • piyush

    thanks alot

  • Zainodis

    Thanks a TON ! Great tutorial :) !

  • Hi… i tried your code but the app force closes. I tried a lot of times but there’s no way i can make it run. I can compile it without any errors though.
    * have used google apis 2.3 as target
    * sdk 1.6
    It force closes when i use “com.google.android.maps” in the manifest file. If i dont use it in my map , then everything seems fine. I’m not sure if its an issue with the eclipse or android. please help.
    please check out the log and let me what exactly is the problem.

    04-29 22:14:32.553: D/dalvikvm(415): GC_CONCURRENT freed 261K, 48% free 2963K/5639K, external 411K/517K, paused 5ms+5ms
    04-29 22:14:32.863: D/dalvikvm(415): GC_CONCURRENT freed 447K, 49% free 3086K/5959K, external 411K/517K, paused 5ms+7ms
    04-29 22:14:33.133: D/dalvikvm(415): GC_CONCURRENT freed 326K, 46% free 3271K/6023K, external 411K/517K, paused 5ms+6ms
    04-29 22:14:33.203: D/AndroidRuntime(415): Shutting down VM
    04-29 22:14:33.203: W/dalvikvm(415): threadid=1: thread exiting with uncaught exception (group=0x40015560)
    04-29 22:14:33.303: E/AndroidRuntime(415): FATAL EXCEPTION: main
    04-29 22:14:33.303: E/AndroidRuntime(415): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.map/com.my.map.MapActivity}: android.view.InflateException: Binary XML file line #6: Error inflating class com.google.android.maps.MapView
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.os.Handler.dispatchMessage(Handler.java:99)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.os.Looper.loop(Looper.java:130)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.ActivityThread.main(ActivityThread.java:3683)
    04-29 22:14:33.303: E/AndroidRuntime(415): at java.lang.reflect.Method.invokeNative(Native Method)
    04-29 22:14:33.303: E/AndroidRuntime(415): at java.lang.reflect.Method.invoke(Method.java:507)
    04-29 22:14:33.303: E/AndroidRuntime(415): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    04-29 22:14:33.303: E/AndroidRuntime(415): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    04-29 22:14:33.303: E/AndroidRuntime(415): at dalvik.system.NativeStart.main(Native Method)
    04-29 22:14:33.303: E/AndroidRuntime(415): Caused by: android.view.InflateException: Binary XML file line #6: Error inflating class com.google.android.maps.MapView
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.view.LayoutInflater.createView(LayoutInflater.java:518)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
    04-29 22:14:33.303: E/AndroidRuntime(415): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.Activity.setContentView(Activity.java:1657)
    04-29 22:14:33.303: E/AndroidRuntime(415): at com.my.map.MapActivity.onCreate(MapActivity.java:17)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
    04-29 22:14:33.303: E/AndroidRuntime(415): … 11 more
    04-29 22:14:33.303: E/AndroidRuntime(415): Caused by: java.lang.reflect.InvocationTargetException
    04-29 22:14:33.303: E/AndroidRuntime(415): at java.lang.reflect.Constructor.constructNative(Native Method)
    04-29 22:14:33.303: E/AndroidRuntime(415): at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
    04-29 22:14:33.303: E/AndroidRuntime(415): at android.view.LayoutInflater.createView(LayoutInflater.java:505)
    04-29 22:14:33.303: E/AndroidRuntime(415): … 21 more
    04-29 22:14:33.303: E/AndroidRuntime(415): Caused by: java.lang.IllegalArgumentException: MapViews can only be created inside instances of MapActivity.
    04-29 22:14:33.303: E/AndroidRuntime(415): at com.google.android.maps.MapView.(MapView.java:291)
    04-29 22:14:33.303: E/AndroidRuntime(415): at com.google.android.maps.MapView.(MapView.java:264)
    04-29 22:14:33.303: E/AndroidRuntime(415): at com.google.android.maps.MapView.(MapView.java:247)
    04-29 22:14:33.303: E/AndroidRuntime(415): … 24 more
    04-29 22:14:45.193: I/Process(415): Sending signal. PID: 415 SIG: 9

    i have attached the log file here separately.
    http://www.filefactory.com/file/490aevj4h1cf/n/log_txt

  • Josh

    Looks like you have a layout issue on line 6 (Caused by: android.view.InflateException: Binary XML file line #6). Can you reply back with your layout.xml file? Or check it again for any simple typos.

  • orastem

    Man, thanks for this. Step 5 allowed me to fix a leak I’ve been struggling with for almost two days.

  • prashant

    thanks!
    this site is very best for code who has trouble in developement.