The Google Play Services version of the Places SDK for Android (i.e. com.google.android.gms:play-services-places) is turned off on July 29, 2019. Now a new version of the Places SDK for Android is available which depends on AndroidX.
In this article, we will talk about how to get current and nearby places of user’s device using a new Google Places library and also how to implement it in google map.
The new version of the Places SDK for Android introduces new methods :
fetchPlace() : Fetches the details about a particular place.
fetchPhoto() : Fetches a photo. The photos service may cache the image data. If the requested photo does not exist in the cache then a network lookup will be performed.
findCurrentPlace() : Fetches the approximate current location of the user’s device. It returns a list of PlaceLikelihoods indicating places where the user’s device is most likely to be located.
findAutocompletePredictions() : It return place predictions in response to user search queries.
Adding the client library
In the dependencies section of your app-level build.gradle file, add a dependency for the new SDK client library, as shown below:
dependencies { implementation 'com.google.android.libraries.places:places:2.0.0' }
Make sure that the minSdkVersion for your application project is 16 or higher
Initialize the new Places SDK client
Initialize the new Places SDK client as shown below:
// Add an import statement for the client library.
import com.google.android.libraries.places.api.Places;
...
// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);
// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);
Now let’s see how to implement this in an example project.
Creating New Project
1 .Create a new project in Android Studio from File ⇒ New Project and fill the project details.
Getting the API key
- Go to Google API Console.
- Create a new project and generate a new API key corresponding to your SHA1 and application package name.
- To integrate google map and to access nearby places in your application enable Maps SDK for Android and Places API.
- Open AndroidManifest.xml and add the generated API key to your project above the application tag as shown below :
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.getnearbyplaces"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <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.geo.API_KEY" android:value="@string/API_KEY" /> </application> </manifest>
2. Open build.gradle and add dependency for the new Places SDK client library to get current and nearby places and also add a dependency for google map as shown below:
build.gradle
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' //library for google map implementation 'com.google.android.gms:play-services-maps:16.1.0' //Places SDK client library implementation 'com.google.android.libraries.places:places:2.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' }
3 .Open AndroidManifest file and add all the permissions which you want to request above the application tag.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.getnearbyplaces"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <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.geo.API_KEY" android:value="@string/API_KEY" /> </application> </manifest>
4. Open the layout file of your main activity (activity_main.xml ). Now add map fragment to show map and one button to get nearby places.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/btn_nearby_places" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_margin="16dp" android:background="@color/colorPrimary" android:text="Find NearBy Places" android:textColor="#FFFFFF" android:textStyle="bold" /> <fragment android:id="@+id/map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
Initialize the new Places SDK client
5 .Open MainActivity.java and inside onCreate() initialize the new Places SDK client as shown below:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize Places. Places.initialize(getApplicationContext(), "AIzaSyCMznC3Jp0dQQTqLkq15qnz-U-kDA2_pHo"); // Create a new Places client instance. placesClient = Places.createClient(this); }
Finding Current Location
Places SDK library provide a method called findCurrentPlace() to find the current location of the user’s device.It returns a list of PlaceLikelihoods indicating places where the user’s device is most likely to be located.
6 .Create a FindCurrentPlaceRequest, including a list of place data types to return.
// Use fields to define the data types to return.
List<Place.Field> placeFields = Arrays.asList(Place.Field.ID,
Place.Field.NAME,Place.Field.ADDRESS);
// Use the builder to create a FindCurrentPlaceRequest.
FindCurrentPlaceRequest request =
FindCurrentPlaceRequest.builder(placeFields).build();
7 .Call findCurrentPlace and handle the response, checking first to verify that the user has granted permission to use their device location.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { placesClient.findCurrentPlace(request).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { FindCurrentPlaceResponse response = task.getResult(); placeLikelihoods = new ArrayList<>(); placeLikelihoods.addAll(response.getPlaceLikelihoods()); //response.getPlaceLikelihoods() will return list of PlaceLikelihood //we need to create a custom comparator to sort list by likelihoods Collections.sort(placeLikelihoods, new Comparator() { @Override public int compare(PlaceLikelihood placeLikelihood, PlaceLikelihood t1) { return new Double(placeLikelihood.getLikelihood()).compareTo(t1.getLikelihood()); } }); //After sort ,it will order by ascending , we just reverse it to get first item as nearest place Collections.reverse(placeLikelihoods); placeId = placeLikelihoods.get(0).getPlace().getId(); latLng = placeLikelihoods.get(0).getPlace().getLatLng(); address = placeLikelihoods.get(0).getPlace().getAddress(); //Removing item of the list at 0 index placeLikelihoods.remove(0); SupportMapFragment supportMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); supportMapFragment.getMapAsync(MainActivity.this); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(MainActivity.this, "Place not found: " + e.getMessage(), Toast.LENGTH_LONG).show(); } }); } else { //Requesting permission if it is not already granted ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE); return; }
Complete Code
8 .Open MainActivity.java and write the below code.
MainActivity.java
package com.example.getnearbyplaces; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.Task; import com.google.android.libraries.places.api.Places; import com.google.android.libraries.places.api.model.Place; import com.google.android.libraries.places.api.model.PlaceLikelihood; import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest; import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse; import com.google.android.libraries.places.api.net.PlacesClient; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; public class MainActivity extends AppCompatActivity implements OnMapReadyCallback { private static final int REQUEST_CODE = 200; PlacesClient placesClient; List placeFields = Arrays.asList(Place.Field.ID, Place.Field.NAME, Place.Field.ADDRESS); Button btn_nearby_places; LatLng latLng; String address; private String placeId; private List placeLikelihoods; GoogleMap map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize Places. Places.initialize(getApplicationContext(), "AIzaSyCMznC3Jp0dQQTqLkq15qnz-U-kDA2_pHo"); // Create a new Places client instance. placesClient = Places.createClient(this); btn_nearby_places = findViewById(R.id.btn_nearby_places); //Get the current place and nearby places of your device getCurrentPlace(); btn_nearby_places.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //setting Marker at nearby places setMarkerAtNearbyPlaces(); } }); } private void getCurrentPlace() { FindCurrentPlaceRequest request = FindCurrentPlaceRequest.builder(placeFields).build(); // Call findCurrentPlace and handle the response (first check that the user has granted permission). if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { placesClient.findCurrentPlace(request).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { FindCurrentPlaceResponse response = task.getResult(); placeLikelihoods = new ArrayList<>(); placeLikelihoods.addAll(response.getPlaceLikelihoods()); //response.getPlaceLikelihoods() will return list of PlaceLikelihood //we need to create a custom comparator to sort list by likelihoods Collections.sort(placeLikelihoods, new Comparator() { @Override public int compare(PlaceLikelihood placeLikelihood, PlaceLikelihood t1) { return new Double(placeLikelihood.getLikelihood()).compareTo(t1.getLikelihood()); } }); //After sort ,it will order by ascending , we just reverse it to get first item as nearest place Collections.reverse(placeLikelihoods); placeId = placeLikelihoods.get(0).getPlace().getId(); latLng = placeLikelihoods.get(0).getPlace().getLatLng(); address = placeLikelihoods.get(0).getPlace().getAddress(); //Removing item of the list at 0 index placeLikelihoods.remove(0); SupportMapFragment supportMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); supportMapFragment.getMapAsync(MainActivity.this); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(MainActivity.this, "Place not found: " + e.getMessage(), Toast.LENGTH_LONG).show(); } }); } else { //Requesting permission if it is not already granted ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE); return; } } private void setMarkerAtNearbyPlaces() { for (PlaceLikelihood place : placeLikelihoods) { MarkerOptions markerOptions = new MarkerOptions().position(place.getPlace().getLatLng()).title(place.getPlace().getAddress()); map.addMarker(markerOptions); } } @Override public void onMapReady(GoogleMap googleMap) { map = googleMap; //Adding marker in map at current location MarkerOptions markerOptions = new MarkerOptions().position(latLng).title(address).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)); googleMap.animateCamera(CameraUpdateFactory.newLatLng(latLng)); googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15)); googleMap.addMarker(markerOptions); } //handling request permission response @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case REQUEST_CODE: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "Permission granted", Toast.LENGTH_LONG).show(); getCurrentPlace(); } else Toast.makeText(this, "Permission denied", Toast.LENGTH_LONG).show(); break; } } }