Google Maps provides Android developers with localization tools that can be included within your own app interfaces. In this series, we are creating a basic Android application with Google Maps and Google Places integration. In this part, we will access the Google Places API to retrieve information about places of interest near the user's current location. We will use the returned data to present markers for each place on the map in the final part of this tutorial series. We will also set the application to update the map markers when the user's location changes.
This is the third of four parts in a tutorial series on Using Google Maps and Google Places in Android apps:
- Working with Google Maps - Application Setup
- Working with Google Maps - Map Setup
- Working with Google Maps - Places Integration
- Working with Google Maps - Displaying Nearby Places (Pending Publication)
1. Get Google Places API Access
Step 1
In the first part of this series we used the Google API Console to get an API key for the mapping tools. Now we need to do the same for the Google Places API. Sign into your Google Account and browse to the Console again. Select Services from the options in the left-hand column and scroll down to the entry for Places API. Click to turn Places on for your account.
Remember you need to carry out this step for any Google API service you wish to access, as your keys will not work otherwise.
Step 2
Now we need to get the key to access the Places API. Select API Access from the left-hand column in your Google APIs Console. You will see the page we used in the first part of the series to retrieve an API key for the mapping package. Although we are going to use the Places API in an Android app, the type of access is actually the same as for browser apps. When we retrieve the Places data, we request it using a URL and retrieve the results in JSON format, as you would in a Web application. Copy the key listed in the Key for browser apps section and save it.
We're finished with the Google APIs Console so feel free to log out of your account.
2. Build a Places Search Query
Step 1
Google Places API provides a range of information about places. For our app, we are going to use the Place Search request to return a list of places near the user's current location. We need to build the necessary elements into a URL query string to execute the Place Search. This is the basic format of the URL:
https://maps.googleapis.com/maps/api/place/nearbysearch/output?parameters
The output can be JSON or XML; we will use JSON for this app. The URL must be appended with various required parameters, including your API key, the user's location as longitude and latitude values, the radius to search within, and a boolean flag indicating whether the location was derived from a location sensor such as a GPS. There are various optional parameters you can add to your query; see the Place Search documentation for an overview. For the purpose of this app, we will add the optional types parameter to search for places of particular types.
This is an indicator of what the final query will look like:
https://maps.googleapis.com/maps/api/place/nearbysearch/json? location=55.864237,-4.251805999999988 &radius=1000 &sensor=true &types=food|bar|store|museum|art_gallery &key=your_api_key
We will build the longitude and latitude values dynamically (the hard-coded example values above are just for demonstration). The radius value is in meters, so feel free to alter it to suit the purpose of your app. You can also alter the place types if you wish; see the Supported Place Types overview for the available options. Make sure you separate the place types using the pipe "|" character. You should of course alter the key parameter value to reflect your own API key.
In your Activity class updatePlaces helper method, after the existing code in which we retrieved the user location and animated the map camera to it, create a string for the Place Search URL:
String placesSearchStr = "https://maps.googleapis.com/maps/api/place/nearbysearch/" + "json?location="+lat+","+lng+ "&radius=1000&sensor=true" + "&types=food|bar|store|museum|art_gallery"+ "&key=your_key_here";
Include the API key you copied from the Google APIs Console for browser apps. Note that we pass the latitude and longitude values we previously retrieved from the user's location.
3. Create an AsyncTask to Fetch Place Data in the Background
Step 1
You will need to add the following import statements to your Activity class for the code we'll use next:
import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.os.AsyncTask;
Since we will fetch data over the Web, we will use an AsyncTask to carry out this process off the UI thread. This will allow us to handle the results within the UI thread, adding markers to the visible map when the app receives the Place Search data.
In your Activity class, create the AsyncTask class outline as follows:
private class GetPlaces extends AsyncTask<String, Void, String> { //fetch and parse place data }
The three types indicated represent the types of parameters, progress units, and the result of the background operation. We will pass the Place Search URL as a string, so this is the parameter. We won't indicate progress for this app, so the second type is void. The result of the background operation in this case will be a JSON string representing the places, so the third type is a text string.
Step 2
When you use an AsyncTask, you indicate the processing you want to occur in the background within the doInBackground method. Once that has executed and retrieved a result, the onPostExecute method will then execute. For this app, we will fetch the Place Search results in doInBackground, then parse the results in onPostExecute, creating markers to display on the map at the same time.
Inside your AsyncTask class, add the doInBackground method:
@Override protected String doInBackground(String... placesURL) { //fetch places }
The parameter type is string, as indicated by the class outline above. Let's use a String Builder to build the returned JSON text string inside this new method:
StringBuilder placesBuilder = new StringBuilder();
Although we will only pass a single Place Search query URL string, the doInBackground method expects to potentially receive an array of parameters, so add a loop to process this:
//process search parameter string(s) for (String placeSearchURL : placesURL) { //execute search }
Inside the loop, create an HTTP Client object to execute the query URL:
HttpClient placesClient = new DefaultHttpClient();
As with any input/output process, we need to take care of potential errors, so add try and catch blocks next, still inside the loop:
try { //try to fetch the data } catch(Exception e){ e.printStackTrace(); }
Inside the try block, create an HTTP Get object, passing the URL string:
HttpGet placesGet = new HttpGet(placeSearchURL);
Use the HTTP Client to execute this, retrieving an HTTP Response:
HttpResponse placesResponse = placesClient.execute(placesGet);
Let's check that we have a positive response before we attempt to carry out any further processing. Retrieve the status line:
StatusLine placeSearchStatus = placesResponse.getStatusLine();
We can only continue if we have a 200 "OK" status code indicating that the request was successful, so add a conditional statement:
if (placeSearchStatus.getStatusCode() == 200) { //we have an OK response }
Inside the if block, retrieve the HTTP Entity from the response object:
HttpEntity placesEntity = placesResponse.getEntity();
Now we can start to retrieve the actual content of the response, which should be the JSON string. Start by creating an Input Stream:
InputStream placesContent = placesEntity.getContent();
Now create a reader for this stream:
InputStreamReader placesInput = new InputStreamReader(placesContent);
Let's carry out our input stream processing using a Buffered Reader:
BufferedReader placesReader = new BufferedReader(placesInput);
Now we can use a loop to read the input one line at a time, appending each one to the String Builder as we go along:
String lineIn; while ((lineIn = placesReader.readLine()) != null) { placesBuilder.append(lineIn); }
This loop will continue to execute as long as there is still data to read in.
Finally, we can return the string that is handled by the String Builder. At the end of the doInBackground method after the for loop, return the JSON data:
return placesBuilder.toString();
Conclusion
The third part of this tutorial series is now complete. We set the app up to utilize Google Places API and created an inner class to fetch the place data in the background off the app's main UI thread. We executed the Place Search query and retrieved the resulting JSON. When you run your app, it will not behave any differently than it did after the previous part of this series. This is because we have not yet completed or instantiated the AsyncTask class. We will do that in the final part, after we add the onPostExecute method to parse the JSON Place Search result and translate it into map markers. We will also extend the app to update the displayed markers as the user's location changes.
Comments