web analytics

How to Create a Google Map Application using Android Studio

Screenshot_2013-12-30-21-40-23

Introduction

In a previous blog, we talked about how to create a simple weather application that showed the current weather on our Android device.  In this blog we are going to delve into GPS and mapping capability on the Android and create a simple app that shows your current location on the map on your device.

Creating a new Project

We will start by creating a simple one blank activity application using Android Studio.  Click on File->New Project in the menu and rename the applcation to MyCurrentLocationOnAMap.

 

image

 

Click through the rest of the wizards and use the default information for the Blank Activity.  Click finish when done, and wait for the project to configure itself and load.  Build and Run the Application to make sure everything is working properly so far.  Be sure to use the Intel emulator as we did in the previous blog post. (The emulator should probably be already fully started before you run the compiled project or else Android Studio may give you an error that says, “Error: Could not access the Package Manager.  Is the system running?”)

 

image

 

After checking the compiled app, we want to remove the hello world and fix the title.  Go to fragment_main.xml and remove the hello_world text widget shown below:

 

image

 

Then fix the title of the app in strings.xml in the app_name string

 

image

 

When you run the app now, it should look like the screen below:

 

image

 

Displaying the Map

The Android library comes with a widget specifically for showing a map on the android called the MapView.  You will need to bring in the Google Api through the SDK Manager in order to use the mapping functionality.  Go to Tools –> Android –> SDK Manager and select the Google API under the library you are building for.  Then click install, you will need to accept the license agreement from google to install the Google api.

image

 

You also need the google libraries containing the google maps api which is in the extra section under Google Play and Google Repositories in the Android SDK manager:

 

image

 

Setting up Permissions in the Manifest

Both GPS and Showing Map Data require permissions in the Android Manifest.  Below is the full manifest that will help get the mapping API working:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.app" >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="myapp.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<uses-library android:name="com.google.android.maps"/><application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.app.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="MYKEY-Rh6VKYwOqZOG88-kM_4giBg-Sg"/>
</application></manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.app" >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="myapp.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<uses-library android:name="com.google.android.maps"/><application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.app.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="MYKEY-Rh6VKYwOqZOG88-kM_4giBg-Sg"/>
</application></manifest>

The Google Play Developer Console

Its not enough to set up the mapping API in Android Studio alone.  You need to obtain an API key and turn on the Map API.  To do this, go to the google play developer console in your google account. If you don’t have a google account, you will need to set one up.  Turn on the Google Maps Android API v2. 

 

image

 

You also need to obtain a key for Google Maps.  Click on Credentials  in the left hand panel of the Developer’s Console and click Create New Key under the Public API access area.

 

image

 

This will generate a long string which you can paste back in your AndroidManifest.xml file in your Android Studio Project shown below:

<meta-data android:name=”com.google.android.maps.v2.API_KEY” android:value=”MYKEY-Rh6VKYwOqZOG88-kM_4giBg-Sg”/>

 

Changing the Build To Include Google Play

In order to use the map libraries included in the google play sdk, you need to bring the dependency into the gradle build file.  Go to build.gradle under the app directory in your Android Studio project.  Add the following dependency to the bottom of the file:

dependencies {
compile ‘com.android.support:appcompat-v7:+’
compile ‘com.google.android.gms:play-services:3.1.36′
}

 

Also, when I was tweaking this to get it to work right, I needed to increase the minimum build in which this would work.  Change the minimum sdk to be 11 and maximum to be 19 in android section of the build.gradle as well:

android {
compileSdkVersion 19
buildToolsVersion “19.0.0″

defaultConfig {
minSdkVersion 11
targetSdkVersion 19
versionCode 1
versionName “1.0″
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.txt’
}
}
}

Coding up the Activity for Mapping

Once we have jumped through all these hoops to get Android Studio prepared to compile and run our map application, we are finally ready to code the map and render it on the screen.  The first thing we need to do is add the map to our layout.  It turns out the easiest way to do this  is to put a MapFragment directly into our MainActivity layout:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.app.MainActivity"
tools:ignore="MergeRootFrame" ><LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"><fragment
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.google.android.gms.maps.MapFragment"
android:id="@+id/map" />
    </LinearLayout>
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.app.MainActivity"
tools:ignore="MergeRootFrame" ><LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"><fragment
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.google.android.gms.maps.MapFragment"
android:id="@+id/map" />
    </LinearLayout>
</FrameLayout>

 

Now we have full access to the map through the fragment.  To access the map in code, we can use the following in our MainActivity:

mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMap();

 

Setting up the MainActivity for receiving GPS Data

In order to get GPS data for our map, we’ll need to make some changes to the activity itself by implementing a LocationListener interface.  To do this, we can simply implement LocationListener on the end of our MainActivity class declaration.  Then we can use the power of Android Studio to generate the interface methods by clicking Alt-Enter on the LocationListener interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.app;import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends ActionBarActivity implements LocationListener 
{
package com.example.app;import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends ActionBarActivity implements LocationListener 
{

 

To use the LocationListener, we just need to make a request to the GPS provider to send us GPS coordinates repeatedly over a predetermined interval which we pass to the request.  Below is the code for retrieving the provider and making the request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
LocationManager locationManager;
 
// Get the LocationManager object from the System Service LOCATION_SERVICE
locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
 
// Create a criteria object needed to retrieve the provider
Criteria criteria = new Criteria();
 
// Get the name of the best available provider
String provider = locationManager.getBestProvider(criteria, true);
 
// We can use the provider immediately to get the last known location
Location location = locationManager.getLastKnownLocation(provider);
 
// request that the provider send this activity GPS updates every 20 seconds
locationManager.requestLocationUpdates(provider, 20000, 0, this);
LocationManager locationManager;

// Get the LocationManager object from the System Service LOCATION_SERVICE
locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);

// Create a criteria object needed to retrieve the provider
Criteria criteria = new Criteria();

// Get the name of the best available provider
String provider = locationManager.getBestProvider(criteria, true);

// We can use the provider immediately to get the last known location
Location location = locationManager.getLastKnownLocation(provider);

// request that the provider send this activity GPS updates every 20 seconds
locationManager.requestLocationUpdates(provider, 20000, 0, this);

 

Once we set up the provider to send requests, we can receive the data in our LocationListener (which happens to be our MainActivity).  We can retrieve the data on the onLocationChange method that was added to our MainActivity when we implemented it as a LocationListener

@Override
public void onLocationChanged(Location location) {
if (mMap != null)
{drawMarker(location);
}
}

 

Inside the LocationListener, we can draw the marker on the map with our current location returned by the GPS provider.  Everytime we move to a new location,  a new marker should be plotted.

 

Drawing the Marker on the Map

We can use the GoogleMap object we retrieved earlier from our MapFragment to manipulate the map programmatically.  First we’ll zoom the map to center on our current location and then we’ll add a marker to the map to mark the current location sent from the GPS:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void drawMarker(Location location){
mMap.clear();
 
//  convert the location object to a LatLng object that can be used by the map API
LatLng currentPosition = new LatLng(location.getLatitude(), location.getLongitude());
 
// zoom to the current location
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentPosition,16));
 
// add a marker to the map indicating our current position
mMap.addMarker(new MarkerOptions()
  .position(currentPosition)
  .snippet("Lat:" + location.getLatitude() + "Lng:"+ location.getLongitude()));
}
private void drawMarker(Location location){
mMap.clear();

//  convert the location object to a LatLng object that can be used by the map API
LatLng currentPosition = new LatLng(location.getLatitude(), location.getLongitude());

// zoom to the current location
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentPosition,16));

// add a marker to the map indicating our current position
mMap.addMarker(new MarkerOptions()
  .position(currentPosition)
  .snippet("Lat:" + location.getLatitude() + "Lng:"+ location.getLongitude()));
}

 

 

Running the Application

Hook up your Android device through USB to your PC.  Go to the Run->Run menu in Android Studio  to run the app.  Choose the device itself, as opposed to the emulator and make sure your device supports both GPS and Google Maps.

 

image

 

If you have done everything correctly including adding all the permissions to the manifest, altering the build.gradle file, installing all the necessary android SDKs, turning on the API in the google play console and retrieving an API key, you should see the map showing up on your device with a marker indicating your current location.

 

A Word About Running in an Emulator

In order to run google api against the emulator, you need to target the google api.  You can’t use the Intel emulator for this, unfortunately.  If you select the target as google API, Android Studio will automatically switch you to the ARM emulator.  Even doing these things, I was unable to run the map through the ARM emulator (which is ridiculously slow).  I got an error, “Google Maps Android API v2 only supports devices with OpenGL ES 2.0 and above”.  Ironically I believe the Intel emulator does support OpenGL ES 2.0.  I saw some advice online from others running into this same exact problem to try an emulator called genymotion, which apparently doesn’t exhibit this unwanted behavior for maps. I believe, though, that genymotion costs $136 for a personal license.  Hopefully Google will update their emulator to address this issue.

Conclusion

Getting the mapping functionality to build and work on my Android device was no simple task in Android Studio.  Hopefully, Google will incorporate some sort of project template to make this task a lot simpler in the future.  In any case, it does eventually work, and once you get to this step, the world is open to the many applications you can invent with mapping and GPS capability at your fingertips in Android Studio.

Share

Share This Post

Related Articles

2 Responses to “How to Create a Google Map Application using Android Studio”

  1. Victor says:

    Hi, this is a awesome guide, but I can’t find out where to put “mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
    .getMap();” in the MainActivity? I always get an error message.

  2. James White says:

    This is by far and away the best example I have come across, however as a novice programmer, you omit to say where in the project to paste the code… Could you possibly expand on this?

Leave a Reply

*

© 2014 ToDroid. All rights reserved.
Disclaimer: The content on this site is copyrighted. Do not copy the content. The content on this site must not be reproduced anywhere else.