Google Places API Tutorial

In this article i am going to talk about how to use Google Places API in Android. The Places API accepts search filter parameters. If you know that you're looking for a place with a particular word or string in its name, or if you're only interested in results that are restaurants, you can pass this information to the Places service for more accurate results.

Getting Started:

  1. Register your android project to get API Key in google console:
    https://code.google.com/apis/console/
  2. Get browser API
Note: Use browser API key rather than android API key.

1. To search for specific types of places (such as cafes), you can include the types parameter in your Places Search requests.

https://maps.googleapis.com/maps/api/place/search/json
  ?types=cafe
  &location=37.787930,-122.4074990
  &radius=5000
  &sensor=false
  &key=YOUR_API_KEY

2. Try specifying multiple place types by modifying the URL below to include other place types separated by a pipe ( | ) character in the URL. The Places Search API will return Places associated with any of the types that you specify. The example below demonstrates how to search for places that are considered a cafe or a bakery or both:
https://maps.googleapis.com/maps/api/place/search/json
  ?types=cafe|bakery
  &location=37.787930,-122.4074990
  &radius=5000
  &sensor=false
  &key=YOUR_API_KEY

3. To retrieve places based by distance:




    1. Remove the radius parameter from your Place Search request.
    2. Add a rankby=distance parameter/value pair.
    3. Include one or more of the keywordname, or types parameters.
For example, the URL below can be used to specify a search for cafes near downtown San Francisco, with results ordered by distance from the location:
https://maps.googleapis.com/maps/api/place/search/json
  ?types=cafe
  &rankby=distance
  &location=37.787930,-122.4074990
  &sensor=false
  &key=YOUR_API_KEY
4. To see more types that support Places API :
https://developers.google.com/places/documentation/supported_types

Place.java :

public class Place {
    private String id;
    private String icon;
    private String name;
    private String vicinity;
    private Double latitude;
    private Double longitude;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getIcon() {
        return icon;
    }
    public void setIcon(String icon) {
        this.icon = icon;
    }
    public Double getLatitude() {
        return latitude;
    }
    public void setLatitude(Double latitude) {
        this.latitude = latitude;
    }
    public Double getLongitude() {
        return longitude;
    }
    public void setLongitude(Double longitude) {
        this.longitude = longitude;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getVicinity() {
        return vicinity;
    }
    public void setVicinity(String vicinity) {
        this.vicinity = vicinity;
    }

    static Place jsonToPontoReferencia(JSONObject pontoReferencia) {
        try {
            Place result = new Place();
            JSONObject geometry = (JSONObject) pontoReferencia.get("geometry");
            JSONObject location = (JSONObject) geometry.get("location");
            result.setLatitude((Double) location.get("lat"));
            result.setLongitude((Double) location.get("lng"));
            result.setIcon(pontoReferencia.getString("icon"));
            result.setName(pontoReferencia.getString("name"));
            result.setVicinity(pontoReferencia.getString("vicinity"));
            result.setId(pontoReferencia.getString("id"));
            return result;
        } catch (JSONException ex) {
            Logger.getLogger(Place.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    @Override
    public String toString() {
        return "Place{" + "id=" + id + ", icon=" + icon + ", name=" + name + ", latitude=" + latitude + ", longitude=" + longitude + '}';
    }

}

PlacesService.java:

public class PlacesService {

 private String API_KEY;

 public PlacesService(String apikey) {
  this.API_KEY = apikey;
 }

 public void setApiKey(String apikey) {
  this.API_KEY = apikey;
 }

 public ArrayList findPlaces(double latitude, double longitude,
   String placeSpacification) {

  String urlString = makeUrl(latitude, longitude, placeSpacification);

  try {
   String json = getJSON(urlString);

   System.out.println(json);
   JSONObject object = new JSONObject(json);
   JSONArray array = object.getJSONArray("results");

   ArrayList arrayList = new ArrayList();
   for (int i = 0; i < array.length(); i++) {
    try {
     Place place = Place
       .jsonToPontoReferencia((JSONObject) array.get(i));
     Log.v("Places Services ", "" + place);
     arrayList.add(place);
    } catch (Exception e) {
    }
   }
   return arrayList;
  } catch (JSONException ex) {
   Logger.getLogger(PlacesService.class.getName()).log(Level.SEVERE,
     null, ex);
  }
  return null;
 }

 // https://maps.googleapis.com/maps/api/place/search/json?location=28.632808,77.218276&radius=500&types=atm&sensor=false&key=apikey
 private String makeUrl(double latitude, double longitude, String place) {
  StringBuilder urlString = new StringBuilder(
    "https://maps.googleapis.com/maps/api/place/search/json?");

  if (place.equals("")) {
   urlString.append("&location=");
   urlString.append(Double.toString(latitude));
   urlString.append(",");
   urlString.append(Double.toString(longitude));
   urlString.append("&radius=1000");
   // urlString.append("&types="+place);
   urlString.append("&sensor=false&key=" + API_KEY);
  } else {
   urlString.append("&location=");
   urlString.append(Double.toString(latitude));
   urlString.append(",");
   urlString.append(Double.toString(longitude));
   urlString.append("&radius=1000");
   urlString.append("&types=" + place);
   urlString.append("&sensor=false&key=" + API_KEY);
  }
  return urlString.toString();
 }

 protected String getJSON(String url) {
  return getUrlContents(url);
 }

 private String getUrlContents(String theUrl) {
  StringBuilder content = new StringBuilder();
  try {
   URL url = new URL(theUrl);
   URLConnection urlConnection = url.openConnection();
   BufferedReader bufferedReader = new BufferedReader(
     new InputStreamReader(urlConnection.getInputStream()), 8);
   String line;
   while ((line = bufferedReader.readLine()) != null) {
    content.append(line + "\n");
   }
   bufferedReader.close();
  }catch (Exception e) {
   e.printStackTrace();
  }
  return content.toString();
 }
}

MainActivity.java:

public class MainActivity extends Activity {

 private final String TAG = getClass().getSimpleName();
 private GoogleMap mMap;
 private String[] places;
 private LocationManager locationManager;
 private Location loc;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  initCompo();
  places = getResources().getStringArray(R.array.places);
  currentLocation();
  final ActionBar actionBar = getActionBar();
  actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
  actionBar.setListNavigationCallbacks(ArrayAdapter.createFromResource(
    this, R.array.places, android.R.layout.simple_list_item_1),
    new ActionBar.OnNavigationListener() {
     @Override
     public boolean onNavigationItemSelected(int itemPosition,
       long itemId) {
      if (loc != null) {
       mMap.clear();
       new GetPlaces(MainActivity.this,
         places[itemPosition].toLowerCase().replace(
           "-", "_")).execute();
      }
      return true;
     }
    });
 }

 private class GetPlaces extends AsyncTask> {

  private ProgressDialog dialog;
  private Context context;
  private String places;

  public GetPlaces(Context context, String places) {
   this.context = context;
   this.places = places;
  }

  @Override
  protected void onPostExecute(ArrayList result) {
   super.onPostExecute(result);
   if (dialog.isShowing()) {
    dialog.dismiss();
   }
   for (int i = 0; i < result.size(); i++) {
    mMap.addMarker(new MarkerOptions()
      .title(result.get(i).getName())
      .position(
        new LatLng(result.get(i).getLatitude(), result
          .get(i).getLongitude()))
      .icon(BitmapDescriptorFactory
        .fromResource(R.drawable.pin))
      .snippet(result.get(i).getVicinity()));
   }
                        CameraPosition cameraPosition = new CameraPosition.Builder()
     .target(new LatLng(result.get(0).getLatitude(), result
       .get(0).getLongitude())) // Sets the center of the map to
           // Mountain View
     .zoom(14) // Sets the zoom
     .tilt(30) // Sets the tilt of the camera to 30 degrees
     .build(); // Creates a CameraPosition from the builder
   mMap.animateCamera(CameraUpdateFactory
     .newCameraPosition(cameraPosition));
  }

  @Override
  protected void onPreExecute() {
   super.onPreExecute();
   dialog = new ProgressDialog(context);
   dialog.setCancelable(false);
   dialog.setMessage("Loading..");
   dialog.isIndeterminate();
   dialog.show();
  }

  @Override
  protected ArrayList doInBackground(Void... arg0) {
   PlacesService service = new PlacesService(
     "Put your project browser API key here");
   ArrayList findPlaces = service.findPlaces(loc.getLatitude(), // 28.632808
     loc.getLongitude(), places); // 77.218276


   for (int i = 0; i < findPlaces.size(); i++) {

    Place placeDetail = findPlaces.get(i);
    Log.e(TAG, "places : " + placeDetail.getName());
   }
   return findPlaces;
  }
 }

 private void initCompo() {
  mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
    .getMap();
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 private void currentLocation() {
  locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

  String provider = locationManager
    .getBestProvider(new Criteria(), false);

  Location location = locationManager.getLastKnownLocation(provider);

  if (location == null) {
   locationManager.requestLocationUpdates(provider, 0, 0, listener);
  } else {
   loc = location;
   new GetPlaces(MainActivity.this,
     places[0].toLowerCase().replace(
       "-", "_")).execute();
   Log.e(TAG, "location : " + location);
  }

 }

 private LocationListener listener = new LocationListener() {

  @Override
  public void onStatusChanged(String provider, int status, Bundle extras) {
  }

  @Override
  public void onProviderEnabled(String provider) {
  }

  @Override
  public void onProviderDisabled(String provider) {
  }

  @Override
  public void onLocationChanged(Location location) {
   Log.e(TAG, "location update : " + location);
   loc = location;
   locationManager.removeUpdates(listener);
  }
 };
}

ScreenShots:



Source Code : Google Places API Demo

Note: Don't forget to add google play service library

Unknown

My name is Karn Shah, I am a software developer living in Ahmedabad,India and my job/hobby is Android. I have been working on the Android platform since 2011 and I hope that sharing what I have learned will help people get proficient in Android faster!

22 comments:

  1. I am getting error in MainActivity.java. will i have to take something in main.xml too?? because i don't understand why u took (R.array.places).

    ReplyDelete
  2. Hi Karn! Very useful article. Any chance you upload the associated layouts? Thanks in advance.

    ReplyDelete
  3. can you please post the source code?

    ReplyDelete
  4. Hi karn shah i am downloading your app it shows stopped unexpected error. Can you help me to solve this thanks.

    ReplyDelete
  5. hai friends you should copy the String.xml file also.

    ReplyDelete
  6. Hi,I m getting only grid view not showing map i m using browser key not able to getting map view.Kindly help me.
    Regards,
    Usha

    ReplyDelete
  7. Hi, Tx for your tutorial, it is very helpful. I have an authentication problem with the keys:
    10-25 14:31:32.758: E/Google Maps Android API(27728): Authorization failure. Please see https://developers.google.com/maps/documentation/android/start for how to correctly set up the map.
    10-25 14:31:32.778: E/Google Maps Android API(27728):
    Ensure that the following correspond to what is in the API Console:
    Package Name: com.ks.googleplaceapidemo,
    API Key: ***myAndroidkey****, Certificate Fingerprint: *** myFingerPrint ***
    With that key, I can access google maps.
    But I don't understand well : In the URL, I should put my API Key for Brower? and in the Manifest, I should put the android key???

    ReplyDelete
  8. i code is fine , but its not showing result.

    i mean it is not able to detect location, i used toast at various steps since no restaurant/selected item was showing up on map . I found that it is not able to detect location , what can be the problem ?

    ReplyDelete
  9. Hi karn. I want to show the near tourist locations. but there isn't travel section in place types
    How do I make it ?

    ReplyDelete
  10. Hi Karn

    I am getting below error. I stuck in this problem since 2 days. Please help me

    04-23 00:40:40.461: E/Place Services(9630): Content : {
    04-23 00:40:40.461: E/Place Services(9630): "error_message" : "This IP, site or mobile application is not authorized to use this API key.",
    04-23 00:40:40.461: E/Place Services(9630): "html_attributions" : [],
    04-23 00:40:40.461: E/Place Services(9630): "results" : [],
    04-23 00:40:40.461: E/Place Services(9630): "status" : "REQUEST_DENIED"
    04-23 00:40:40.461: E/Place Services(9630): }


    I have tried all possible solutions. I change android key, server key. I have set key in manifest. I have place API on. I am still not able to find reason for getting this error.

    ReplyDelete
  11. java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ks.googleplaceapidemo/com.ks.googleplaceapidemo.MainActivity}: android.view.InflateException: Binary XML file line #2: Error inflating class fragment


    ERROr help..

    ReplyDelete






  12. the apps the working fine when its Dialog box initiation it does show show which i mention below arrayout of bound plz tell me what should i do......thnx in advance waiting your desire full response ......








    04-28 12:29:13.456: E/AndroidRuntime(2020): FATAL EXCEPTION: main
    04-28 12:29:13.456: E/AndroidRuntime(2020): java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
    04-28 12:29:13.456: E/AndroidRuntime(2020): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at java.util.ArrayList.get(ArrayList.java:304)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at com.ks.googleplaceapidemo.MainActivity$GetPlaces.onPostExecute(MainActivity.java:108)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at com.ks.googleplaceapidemo.MainActivity$GetPlaces.onPostExecute(MainActivity.java:1)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at android.os.AsyncTask.finish(AsyncTask.java:631)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at android.os.AsyncTask.access$600(AsyncTask.java:177)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at android.os.Handler.dispatchMessage(Handler.java:99)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at android.os.Looper.loop(Looper.java:137)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at android.app.ActivityThread.main(ActivityThread.java:4947)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at java.lang.reflect.Method.invokeNative(Native Method)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at java.lang.reflect.Method.invoke(Method.java:511)
    04-28 12:29:13.456: E/AndroidRuntime(2020): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)

    ReplyDelete
  13. I generate SHA 1 for my machine and display map properly. But when i generate Browser Key and use that key as API KEY in PLACE API then it shows me below error:

    {
    "error_message" : "This IP, site or mobile application is not authorized to use this API key.",
    "html_attributions" : [],
    "results" : [],
    "status" : "REQUEST_DENIED"
    }

    I also generate Server Key by adding my IP Address. But that key is also not working.

    What's an issue is that? I can't find it.

    Thanks for help in advance.

    ReplyDelete
  14. Hello,

    when I select any of the places I got nothing...the map doesn't change at all..
    and I got these error
    Could not find class 'gpr', referenced from method gps.a

    do you have any suggestions please?

    Thanks for your help.

    ReplyDelete
  15. how do you search for multiple types in Java? The pipe character triggers an error.

    ReplyDelete
  16. places[0].toLowerCase().replace("-", "_")).execute() why we use this?
    specially this one .replace("-", "_")).execute() can u plz explain?

    ReplyDelete
  17. im having trouble running the sample app, i downloaded it from github and imported google playservices and im getting this error

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ks.googleplaceapidemo/com.ks.googleplaceapidemo.MainActivity}: android.view.InflateException: Binary XML file line #2: Error inflating class fragment

    ReplyDelete
  18. Nice tutorial, But I have a query, How to get the contact number of near by police stations, this api returns the other details about the police stations but contact number is not returning.

    ReplyDelete
  19. According to this(https://developers.google.com/places/documentation/search), search api can't retrieve phone number, You need to use information about "id" in place details api to get more detail info like(phone number etc)

    ReplyDelete