Introduction
In March of 2015, Google released the Places API for Android as a part of Google's Play Services. This API allows developers to access a wealth of information from Google to provide users with an experience tailored to their current location by using the names and information of places, rather than a set of coordinates.
Google Places API for Android includes six new features:
If you don't already have an Android public API key, you will need to create a public Google API key for Android applications. You can do this by visiting the Google's Developers Console. Instructions for creating a key based on your signing certificate and package name are available in Google's documentation.
When you've created a key, search for the Places API and set it to enabled. Some calls to the Places API are limited in how many requests can be sent per 24 hour period. At the time of writing, an account without a billing profile can send up to 1,000 requests while an account with a billing profile can send 150,000 requests. If you require more, you can submit a request to have this limit increased as described in the Usage Limits documentation.
With the API key ready to use, it is time to start working on the demo project. Create a project in Android Studio and set the minimum supported SDK version to at least 9. This is the minimum requirement for using Google's Play Services.
Open the build.gradle file and, under the dependencies node, add the required dependency of Play Services 10.2.4. This is the latest at the time of writing, but you can verify the latest version by checking Google's documentation.
dependencies { ... // for real device // compile 'com.google.android.gms:play-services:10.2.4' // for emulator compile 'com.google.android.gms:play-services:8+' }
Next, open AndroidManifest.xml, add the required permissions for the project, and state that OpenGL version 2 is required by the application.
<uses-feature android:glEsVersion="0x00020000" android:required="true" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application> ... </application>
The last thing you will need to do in the manifest is adding <meta-data>
tag to set the API key for the app within the <application>
tag.
<meta-data android:name="com.google.android.geo.API_KEY" android:value="@string/google_api_key" />
When you're done with the manifest, you are ready to start writing code. As this is a component from Play Services, you will need to initialize your GoogleApiClient
and connect/disconnect it during your Activity's life cycle. We do this in the onCreate
, onStart
, and onStop
methods of the Activity class.
GoogleApiClient gac; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvPlace = (TextView) findViewById(R.id.tvPlace); gac = new GoogleApiClient .Builder(this) .addApi(Places.GEO_DATA_API) .addApi(Places.PLACE_DETECTION_API) .enableAutoManage(this, this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); } @Override protected void onStart() { super.onStart(); if (gac != null) gac.connect(); } @Override protected void onStop() { if (gac != null && gac.isConnected()) { gac.disconnect(); } super.onStop(); }
Place Picker
The PlacePicker
widget is a user interface component provided by Play Services that allows the user to see a map of their surrounding area. The component includes a list of nearby places that can be used by your app. By using this component, you are able to follow a standard design that your users will know how to interact with while being able to save on development time.
To use the PlacePicker
, you need to create an intent and listen for the Activity result to retrieve the Place selected by the user. The following method shows how you would launch this Activity.
public void getPlace(View v) { if(gac == null || !gac.isConnected()) return; PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); try { startActivityForResult(builder.build(this), PLACE_PICKER_REQUEST); } catch ( GooglePlayServicesRepairableException e) { Log.d(TAG, "GooglePlayServicesRepairableException thrown"); } catch ( GooglePlayServicesNotAvailableException e) { Log.d(TAG, "GooglePlayServicesNotAvailableException thrown"); } }
The PlacePicker.IntentBuilder
is used to create the Intent
that will be used to launch the PlacePicker
. It also has an method available, setLatLngBounds()
, that lets you place a geographic boundary from a southwest corner to a northeast corner to control the search area.
The Intent can be built using the build method from PlacePicker.IntentBuilder
and launched using the startActivityForResult()
method from your Activity. It should be noted that using the build method does have the possibility of throwing a GooglePlayServicesRepairableException
or a GooglePlayServicesNotAvailableException
exception, so those should be checked for using a standard try/catch block and handled gracefully if they occur.
If the user selects a location from the place picker list, that Place
object is packaged into an Intent
and sent back to the calling Activity. Using the PlacePicker.getPlace
method, you can extract the Place
data from the returned Intent
.
protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PLACE_PICKER_REQUEST && resultCode == RESULT_OK) { displayPlace(PlacePicker.getPlace( data, this )); } }
Once the Place
object is extracted, it can be treated as a model object to display or use within your app.
private void displayPlace(Place place) { if (place == null) return; StringBuilder builder = new StringBuilder(); if(!TextUtils.isEmpty(place.getName())) { builder.append("Name: " + place.getName() + "\n"); } if(!TextUtils.isEmpty(place.getAddress())) { builder.append("Address: " + place.getAddress() + "\n"); } if(!TextUtils.isEmpty(place.getPhoneNumber())) { builder.append("Phone: " + place.getPhoneNumber()); } tvPlace.setText(builder.toString()); }
Full code of MainActivity.java is below.
public class MainActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { int PLACE_PICKER_REQUEST = 1; String TAG = "GPLACES"; GoogleApiClient gac; TextView tvPlace; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvPlace = (TextView) findViewById(R.id.tvPlace); gac = new GoogleApiClient .Builder(this) .addApi(Places.GEO_DATA_API) .addApi(Places.PLACE_DETECTION_API) .enableAutoManage(this, this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); } public void getPlace(View v) { if(gac == null || !gac.isConnected()) return; PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); try { startActivityForResult(builder.build(this), PLACE_PICKER_REQUEST); } catch ( GooglePlayServicesRepairableException e) { Log.d(TAG, "GooglePlayServicesRepairableException thrown"); } catch ( GooglePlayServicesNotAvailableException e) { Log.d(TAG, "GooglePlayServicesNotAvailableException thrown"); } } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PLACE_PICKER_REQUEST && resultCode == RESULT_OK) { displayPlace(PlacePicker.getPlace( data, this )); } } private void displayPlace(Place place) { if (place == null) return; StringBuilder builder = new StringBuilder(); if(!TextUtils.isEmpty(place.getName())) { builder.append("Name: " + place.getName() + "\n"); } if(!TextUtils.isEmpty( place.getAddress())) { builder.append("Address: " + place.getAddress() + "\n"); } if(!TextUtils.isEmpty( place.getPhoneNumber())) { builder.append("Phone: " + place.getPhoneNumber()); } tvPlace.setText(builder.toString()); } @Override public void onConnected(@Nullable Bundle bundle) { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED) { Toast.makeText(ThirdActivity.this, "Please allow ACCESS_COARSE_LOCATION persmission.", Toast.LENGTH_LONG).show(); return; } } @Override protected void onStart() { super.onStart(); if (gac != null) gac.connect(); } @Override protected void onStop() { if (gac != null && gac.isConnected()) { gac.disconnect(); } super.onStop(); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {} @Override public void onConnectionSuspended(int i) {} }
Layout of activity_main.xml is below.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:orientation="vertical"> <Button android:text="Get place" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="getPlace"/> <TextView android:id="@+id/tvPlace" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
Place Autocomplete
The autocomplete service in the Google Places API for Android returns place predictions in response to user search queries. As the user types, the autocomplete service returns suggestions for places such as businesses, addresses and points of interest.
You can add autocomplete to your app in the following ways:
Add an autocomplete widget
The autocomplete widget is a search dialog with built-in autocomplete functionality. As a user enters search terms, the widget presents a list of predicted places to choose from. When the user makes a selection, a Place instance is returned, which your app can then use to get details about the selected place.
There are two options for adding the autocomplete widget to your app:
You can launch autocomplete by using an Intent
when user click on icon or any other widget. To launch the autocomplete widget using an intent, follow these steps:
PlaceAutocomplete
mode. The intent must call startActivityForResult
, passing in a request code that identifies your intent.onActivityResult
callback to receive the selected place.The Layout and MainActivity is the same like in previous example. Just update getPlace()
and onActivityResult()
methods.
The example below shows using PlaceAutocomplete.IntentBuilder
to create an intent to launch the autocomplete widget as an intent.
public void getPlace(View v) { if(gac == null || !gac.isConnected()) return; try { PlaceAutocomplete.IntentBuilder builder = new PlaceAutocomplete. IntentBuilder(PlaceAutocomplete.MODE_OVERLAY); Intent intent = builder.build(this); startActivityForResult(intent, PLACE_PICKER_REQUEST); } catch ( GooglePlayServicesRepairableException e) { Log.d(TAG, "GooglePlayServicesRepairableException thrown"); } catch ( GooglePlayServicesNotAvailableException e) { Log.d(TAG, "GooglePlayServicesNotAvailableException thrown"); } }
When using an intent to launch the autocomplete widget, you can choose from overlay or full-screen display modes.
To receive notification when a user has selected a place, your app should override the activity's onActivityResult()
, checking for the request code you have passed for your intent, as shown in the following example.
protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PLACE_PICKER_REQUEST && resultCode == RESULT_OK) { displayPlace(PlaceAutocomplete.getPlace(this, data)); } else if (resultCode == PlaceAutocomplete.RESULT_ERROR) { Status status = PlaceAutocomplete.getStatus(this, data); Log.e(TAG, status.getStatusMessage()); } else if (resultCode == RESULT_CANCELED) { // the user canceled the operation. } }
You can set the autocomplete widget to bias results to a specific geographic region, and/or filter the results to one or more place types.
To bias autocomplete results to a specific geographic region call setBoundsBias()
off your IntentBuilder
instance and pass a LatLngBounds.
builder.setBoundsBias(new LatLngBounds( new LatLng(-33.880490, 151.184363), new LatLng(-33.858754, 151.229596)));
You may restrict results from a Place Autocomplete request to be of a certain type by passing a types parameter, call AutocompleteFilter.Builder to create a new AutocompleteFilter
, calling setTypeFilter()
to set the filter to use. Then, pass the filter to a intent.
AutocompleteFilter typeFilter = new AutocompleteFilter.Builder() .setTypeFilter(AutocompleteFilter.TYPE_FILTER_ADDRESS) .build(); Intent intent = builder.setFilter(typeFilter).build(this);
To filter autocomplete results to a specific country, call AutocompleteFilter.Builder
to create a new AutocompleteFilter
, calling setCountry() to set the country code. Then, pass the filter to a Intent.
Adding PlaceAutoCompleteFragment in Activity
You might require searching locations on google map. So we will display map, the user can search a location on the map, and then we will show the marker at the searched location on the map.
Go to your app level build.gradle file and make sure the following dependencies are added.
dependencies { ... implementation 'com.google.android.gms:play-services-maps:12.0.1' implementation 'com.google.android.gms:play-services-places:12.0.1' }
Now come inside the file activity_main.xml. You need to modify your code as shown below.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/place_autocomplete_fragment" android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment" android:layout_width="match_parent" android:layout_height="wrap_content" /> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/place_autocomplete_fragment" /> </RelativeLayout>
Enabling Places API
Now go to MapsActivity.java and here you will find the below code that is available by default.
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback { private GoogleMap map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); PlaceAutocompleteFragment autocompleteFragment = (PlaceAutocompleteFragment) getFragmentManager().findFragmentById(R.id.place_autocomplete_fragment); autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() { @Override public void onPlaceSelected(Place place) { map.clear(); map.addMarker(new MarkerOptions().position(place.getLatLng()).title(place.getName().toString())); map.moveCamera(CameraUpdateFactory.newLatLng(place.getLatLng())); map.animateCamera(CameraUpdateFactory.newLatLngZoom(place.getLatLng(), 12.0f)); } @Override public void onError(Status status) {} }); } @Override public void onMapReady(GoogleMap googleMap) { map = googleMap; LatLng sydney = new LatLng(49.2400, 28.4811); map.addMarker(new MarkerOptions().position(sydney).title("Vinnytsia")); map.moveCamera(CameraUpdateFactory.newLatLng(sydney)); } }
Now thats it, run your application.
Searching for a Place by ID
This section covers finding a Place
object based on its ID. This works similarly to the other API calls by creating a PendingIntent
and interacting with a returned buffer to retrieve the place. The PlaceBuffer
must call release
to avoid any memory leaks.
private void findPlaceById(String id) { if (TextUtils.isEmpty(id) || gac == null || !gac.isConnected()) return; Places.GeoDataApi.getPlaceById(gac, id).setResultCallback(new ResultCallback<PlaceBuffer>() { @Override public void onResult(PlaceBuffer places) { if(places.getStatus().isSuccess()) { Place place = places.get(0); displayPlace(place); } // release the PlaceBuffer to prevent a memory leak places.release(); } }); }
Get photos by Place ID
Places.GeoDataApi.getPlacePhotos(gac, id).setResultCallback(new ResultCallback<PlacePhotoMetadataResult>() { @Override public void onResult(@NonNull PlacePhotoMetadataResult placePhotoMetadataResult) { if (placePhotoMetadataResult.getStatus().isSuccess()) { PlacePhotoMetadataBuffer photoMetadataBuffer = placePhotoMetadataResult.getPhotoMetadata(); PlacePhotoMetadata photoMetadata = photoMetadataBuffer.get(0); photoMetadata.getPhoto(gac).setResultCallback(new ResultCallback<PlacePhotoResult>() { @Override public void onResult(@NonNull PlacePhotoResult placePhotoResult) { Bitmap photo = placePhotoResult.getBitmap(); } }); } } });
AutoCompleteTextView
You maybe know that there are several Google Places services that we can request via HTTP:
place_id
or a reference
from a Place Search, you can request more details about a particular establishment or point of interest by initiating a Place Details request. A Place Details request returns more comprehensive information about the indicated place such as its complete address, phone number, user rating and reviews.In this section we'll use AutoCompleteTextView, Retrofit and Place Autocomplete to search nearest places.
You should go through the Place Autocomplete service documentation where you can learn everything about the requests and responses. Basically you’ll have to make a request to /https://maps.googleapis.com/maps/api/place/autocomplete/output?parameters* where output can be either json or xml indicating the type of expected response. There are 2 required GET parameters which are input
that should contain the string (that the user will type) to use as the search term and key
which should contain your API key. So then the URL will look something like this:
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=Fountain&key=API_KEY
Adding Place Autocomplete to an Android app is fairly easy. All we have to do is issue search requests to the Place API over HTTP and parse the JSON/XML response to display the results in an AutoCompleteTextView
. The requests issued are just like any other request from any type of client like a web browser or a server-side programming language.
As the user types something inside the AutoCompleteTextView
, the filter()
method on the Filter
object returned by getFilter()
will be called that'll trigger performFiltering()
(asynchronously in a background thread). This method calls the getItems()
method which makes the HTTP calls to the Places API returning results for the string/text entered by the user. The API does a substring match against its database of places and returns a result containing predictions
which are basically a list of the places found. The predictions
are stored in an ArrayList
which are then used to populate the AutoCompleteTextView
internally by the getView()
method of ArrayAdapter
.
When an item from the AutoCompleteTextView
's list is selected, we can get the data associated with that list item, i.e., the selection made (from the ArrayList
used as the data source by the adapter).
Have a look at the layout:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="20dp" > <AutoCompleteTextView android:id="@+id/autoCompleteTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="Please enter your place" > <requestFocus /> </AutoCompleteTextView> <ImageView android:id="@+id/ivPhoto" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/tvPlace" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
Also create another layout file (res/layout/autocomplete_list_item.xml) that'll hold the views representing each entry inside the AutoCompleteTextView
:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:id="@+id/autocompleteText" />
Following is the MainActivity.java file.
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { String TAG = "PLACE"; PlaceAutocompleteAPI.ApiInterface api; List<PlaceSerializer.Place> places = new ArrayList<>(); TextView tvPlace; ImageView ivPhoto; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); api = PlaceAutocompleteAPI.getClient().create(PlaceAutocompleteAPI.ApiInterface.class); tvPlace = (TextView) findViewById(R.id.tvPlace); ivPhoto = (ImageView) findViewById(R.id.ivPhoto); AutoCompleteTextView autoCompView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView); autoCompView.setAdapter(new GooglePlacesAutocompleteAdapter(this, R.layout.autocomplete_list_item)); autoCompView.setOnItemClickListener(this); } public void onItemClick(AdapterView adapterView, View view, int position, long id) { String key = PlaceAutocompleteAPI.KEY; PlaceSerializer.Place place = places.get(position); Call<PlaceDetailSerializer> callPlace = api.getPlace(key, place.getPlaceID()); callPlace.enqueue(new Callback<PlaceDetailSerializer>() { @Override public void onResponse(Call<PlaceDetailSerializer> call, Response<PlaceDetailSerializer> response) { Log.e(TAG, "onResponse"); if (response.isSuccessful()) { PlaceDetailSerializer data = response.body(); PlaceDetailSerializer.Place placeDetail = data.getPlace(); tvPlace.setText(placeDetail.getName() + "\n" + placeDetail.getAddress()); Glide.with(ThirdActivity.this).load(placeDetail.getPhotoURL(200)).into(ivPhoto); } } @Override public void onFailure(Call<PlaceDetailSerializer> call, Throwable t) { Log.e(TAG, "onFailure"); Log.e(TAG, t.toString()); } }); String str = (String) adapterView.getItemAtPosition(position); Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); } class GooglePlacesAutocompleteAdapter extends ArrayAdapter implements Filterable { private ArrayList<String> resultList = new ArrayList<>(); public GooglePlacesAutocompleteAdapter(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() { Log.d(TAG, "getFilter"); Filter filter = new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults filterResults = new FilterResults(); if (constraint != null) { // Retrieve the autocomplete results. if (constraint.length() > 2) resultList = getItems(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; } public ArrayList<String> getItems(String input) { ArrayList<String> resultList = new ArrayList<String>(); String key = PlaceAutocompleteAPI.KEY; Call<PlaceSerializer> callPlaces = api.getPredictions(key, input); // show url Log.d(TAG, callPlaces.request().url().toString()); try { PlaceSerializer predictions = callPlaces.execute().body(); places = predictions.getPlaces(); if (!places.isEmpty()) { resultList = new ArrayList<>(); for (PlaceSerializer.Place place : places) { resultList.add(place.getDescription()); Log.d(TAG, place.getDescription()); } } } catch (IOException e) { Log.e(TAG, "Error connecting to Places API", e); return resultList; } return resultList; } } }
In following PlaceAutocompleteAPI
class we define entry url for list and detail of Place API.
public class PlaceAutocompleteAPI { public static String KEY = "*****"; public static final String BASE_URL = "https://maps.googleapis.com/maps/api/place/"; private static Retrofit retrofit = null; public interface ApiInterface { @GET("autocomplete/json") Call<PlaceSerializer> getPredictions( @Query("key") String key, @Query("input") String input ); @GET("details/json") Call<PlaceDetailSerializer> getPlace( @Query("key") String key, @Query("placeid") String placeid ); } public static Retrofit getClient() { if (retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); } return retrofit; } }
We need class that describe list of places.
public class PlaceSerializer { public class Place { @SerializedName("place_id") private String placeID; @SerializedName("description") private String description; @SerializedName("types") private String[] types; public Place(String placeID, String description, String[] types) { this.placeID = placeID; this.description = description; this.types = types; } public String getPlaceID() { return placeID; } public String getDescription() { return description; } public String[] getTypes() { return types; } @Override public String toString() { return "Place{" + "description='" + description + '\'' + '}'; } } @SerializedName("predictions") private List<Place> predictions; @SerializedName("status") private String status; public List<Place> getPlaces() { return predictions; } public String getStatus() { return status; } }
Also we need class that describe details of place.
public class PlaceDetailSerializer { public class Geometry { public class Location { Double lat; Double lng; } Location location; } public class AddressComponent { String long_name; String short_name; String[] types; } public class Photo { int height; int width; String photo_reference; } public class Place { @SerializedName("place_id") private String place_id; @SerializedName("name") private String name; @SerializedName("address_components") private List<AddressComponent> address_components; @SerializedName("formatted_address") private String formatted_address; @SerializedName("international_phone_number") private String phone_number; @SerializedName("photos") private List<Photo> photos; @SerializedName("geometry") private Geometry geometry; @SerializedName("icon") private String icon; @SerializedName("rating") Double rating; @SerializedName("types") private String[] types; @SerializedName("url") private String url; @SerializedName("vicinity") private String vicinity; @SerializedName("website") private String website; public String getID() { return place_id; } public String getName() { return name; } public String getAddress() { return formatted_address; } public List<Photo> getPhotos() { return photos; } public String getPhotoURL(int maxwidth) { if (!photos.isEmpty()) { String key = PlaceAutocompleteAPI.KEY; Photo photo = photos.get(0); String ref = photo.photo_reference; String url = String.format("https://maps.googleapis.com/maps/api/place/ photo?maxwidth=%d&photoreference=%s&key=%s", maxwidth, ref, key); return url; } return null; } @Override public String toString() { return "Place{" + "name='" + name + '\'' + '}'; } } @SerializedName("result") private Place result; @SerializedName("status") private String status; public Place getPlace() { return result; } }
Java Client for Google Maps Services
We can use google-maps-services-java for nearby search.
GeoApiContext geoApiContext = new GeoApiContext.Builder() .apiKey(KEY) .build(); NearbySearchRequest reqNearby = new NearbySearchRequest(geoApiContext); reqNearby.location(new LatLng(49.2258522,28.4129088)); reqNearby.radius(100); try { PlacesSearchResponse respNearby = reqNearby.await(); PlacesSearchResult[] items = respNearby.results; for (PlacesSearchResult item : items) { Log.d(TAG, "Place: " + item.name + ", " + item.rating + ", " + Arrays.asList(types)); } } catch (ApiException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
Also we can see place on Google map via following url https://www.google.com/maps/place/?q=place_id:ChIJBwLpy6NcLUcRsGyvbGx-waA.
Useful links