Google Developers Academy

Adding Place Autocomplete to your Android App

Learning objectives
  • Add the Place Autocomplete service to your Android app.
Prerequisites
  • Android development experience.

You can easily add Place Autocomplete to a variety of applications, regardless of whether they’re web or native applications. Since you access the API using HTTP, you can use just about any type of client or modern language to issue search requests and return responses in formats that can be easily parsed.

This section shows you how to add Autocomplete into an Android application, and includes some sample code.

Overview

To give users the benefit of predictive search, your application should send a query request to the Autocomplete API as the user types characters into an input box. The best way to do this is to set up a listener for the keyup event on the input box, and then to use the value of the string in the input box as the value for the input parameter in your request. You can display the results in a variety of ways, including as a list directly below the input box or on some other element in your application’s user interface.

Note: If you find that your app is reaching the usage limits for the Autocomplete API very quickly, it may be because you are sending requests too quickly. One approach is to set a timeout for the input box so that requests are made to the API when a user pauses typing, thereby reducing the number of total requests made to the service.

Integrating Autocomplete

For example, if you’re working on an Android application, you can integrate the Autocomplete API using the code below:

private static final String LOG_TAG = "ExampleApp";

private static final String PLACES_API_BASE = "https://maps.googleapis.com/maps/api/place";
private static final String TYPE_AUTOCOMPLETE = "/autocomplete";
private static final String OUT_JSON = "/json";

private static final String API_KEY = "YOUR_API_KEY";

private ArrayList<String> autocomplete(String input) {
    ArrayList<String> resultList = null;

    HttpURLConnection conn = null;
    StringBuilder jsonResults = new StringBuilder();
    try {
        StringBuilder sb = new StringBuilder(PLACES_API_BASE + TYPE_AUTOCOMPLETE + OUT_JSON);
        sb.append("?sensor=false&key=" + API_KEY);
        sb.append("&components=country:uk");
        sb.append("&input=" + URLEncoder.encode(input, "utf8"));

        URL url = new URL(sb.toString());
        conn = (HttpURLConnection) url.openConnection();
        InputStreamReader in = new InputStreamReader(conn.getInputStream());

        // Load the results into a StringBuilder
        int read;
        char[] buff = new char[1024];
        while ((read = in.read(buff)) != -1) {
            jsonResults.append(buff, 0, read);
        }
    } catch (MalformedURLException e) {
        Log.e(LOG_TAG, "Error processing Places API URL", e);
        return resultList;
    } catch (IOException e) {
        Log.e(LOG_TAG, "Error connecting to Places API", e);
        return resultList;
    } finally {
        if (conn != null) {
            conn.disconnect();
        }
    }

    try {
        // Create a JSON object hierarchy from the results
        JSONObject jsonObj = new JSONObject(jsonResults.toString());
        JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");

        // Extract the Place descriptions from the results
        resultList = new ArrayList<String>(predsJsonArray.length());
        for (int i = 0; i < predsJsonArray.length(); i++) {
            resultList.add(predsJsonArray.getJSONObject(i).getString("description"));
        }
    } catch (JSONException e) {
        Log.e(LOG_TAG, "Cannot process JSON results", e);
    }

    return resultList;
}

You can use this method to populate the suggestions of an Android AutoCompleteTextView. To do so, you will need a custom ListAdapter (ArrayAdapter implements the ListAdapter interface) to provide Place Autocomplete results to the AutoCompleteTextView.

Your custom Adapter must implement the Filterable interface in order for you to capture the user input from the AutoCompleteTextView and pass it to the Place Autocomplete service.

private class PlacesAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {
    private ArrayList<String> resultList;

    public PlacesAutoCompleteAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);
    }

    @Override
    public int getCount() {
        return resultList.size();
    }

    @Override
    public String getItem(int index) {
        return resultList.get(index);
    }

    @Override
    public Filter getFilter() {
        Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint != null) {
                    // Retrieve the autocomplete results.
                    resultList = autocomplete(constraint.toString());

                    // Assign the data to the FilterResults
                    filterResults.values = resultList;
                    filterResults.count = resultList.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results != null && results.count > 0) {
                    notifyDataSetChanged();
                }
                else {
                    notifyDataSetInvalidated();
                }
            }};
        return filter;
    }
}

You must instantiate your custom Adapter and assign it to the AutoCompleteTextView.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    AutoCompleteTextView autoCompView = (AutoCompleteTextView) findViewById(R.id.autocomplete);
    autoCompView.setAdapter(new PlacesAutoCompleteAdapter(this, R.layout.list_item));

    …
}

To instantiate an ArrayAdapter, you must include a reference to a layout file that contains a TextView for displaying each autocomplete result. In the code above, the reference is R.layout.list_item, which corresponds to the Android layout file res/layout/list_item.xml.

<!-- res/layout/list_item.xml -->
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Detecting when a suggestion has been selected

Finally, if you wish to detect when a suggestion has been selected by the user, implement the OnItemClickListener interface and assign it to the AutoCompleteTextView.

public class PlacesAutocompleteActivity extends Activity implements OnItemClickListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        AutoCompleteTextView autoCompView = (AutoCompleteTextView) findViewById(R.id.autocomplete);
        autoCompView.setAdapter(new PlacesAutoCompleteAdapter(this, R.layout.list_item));
        autoCompView.setOnItemClickListener(this);

    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
        String str = (String) adapterView.getItemAtPosition(position);
        Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
    }

    …
}

API keys

The Place Autocomplete service is part of the Google Places API, and uses an API key to identify your application. API keys are managed through the Google APIs Console.

What type of API key?

You'll need your own browser or server API key for the Google Places API before you can begin using the Place Autcomplete service. Note that an Android API key will not work for the Place Autocomplete service.

Storing your API key

Although the above code demonstrates how to communicate directly between an Android app and the Place Autocomplete service, you should not store your Places API key with your app.

You should therefore build a web application that stores your API key and proxies the Places API services. In order to secure communication between your Android app and the proxy web service, you should require user authentication to your proxy web service. Your Android app can securely store user credentials and pass them to your web service, or the user can log into your web app via an Android WebView.

For the latter approach, your web app should create and return a user authentication token to your Android app, and your Android app should subsequently pass this token to your proxy web service.

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.