Saturday, 14 January 2017

Introduction to Google Maps API for Android

From fitness apps such as Runkeeper to games such as Pokemon Go, location services are an
increasingly important part of modern apps.
In this Google Maps API tutorial, you will create an app named City Guide. The app allows a user to search for a location, use Google Maps to show the address of the location and listen for the user’s location changes.
You will learn how to use the Google Maps Android API, the Google Location Services API and the Google Places API for Android to do the following:
  • Show a user’s current location
  • Display and customize markers on a map
  • Retrieve the address of a location given the coordinates
  • Listen for location updates
  • Search for places
Note: This Google Maps API tutorial assumes you are already familiar with the basics of Android development. If you are completely new to Android development, read through our Android Tutorial for Beginners to familiarize yourself with the basics.

Getting Started

Open Android Studio and select Start a new Android Studio project from the Quick Start menu:
mapping_start_project_1
In the Create New Project dialog, on the New Project view, enter the name of the app as City Guide, select your prefered folder location for the project files and click Next.
google_maps_api_create_project
On the Target Android Devices view, check the Phone and Tablet box and select the minimum SDK you want the app to support. Specify API 14 from the Minimum SDK drop down and click Next.
google_maps_api_tutorial_select_sdk
On the Add an Activity to Mobile view, select the Google Maps Activity and click Next.
select_google_maps_activity
On the Customize the Activity view, click Finish to complete the project creation process.
customize_Activity
Android Studio will start Gradle and build your project. This may take a few seconds.
Open MapsActivity.java. It should look like this:
package com.raywenderlich.cityguide;
 
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
 
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.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
 
// 1
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
 
  private GoogleMap mMap;
 
  // 2
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
        .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
  }
 
  // 3
  @Override
  public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
 
    // Add a marker in Sydney and move the camera
    LatLng sydney = new LatLng(-34, 151);
    mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
    mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
  }
}
  1. MapsActivity currently implements the OnMapReadyCallback interface and extends FragmentActivity.
  2. The class overrides FragmentActivity’s onCreate() method
  3. You also override OnMapReadyCallback’s onMapReady() method. This method is called when the map is ready to be used. The code declared in this method creates a marker with coordinates near Sydney, Australia and adds the marker to the map.
The template adds the following in the manifests/AndroidManifest.xml:
  1. A declaration of the ACCESS_FINE_LOCATION permission. This is required to access the user’s precise location.
  2. The com.google.android.geo.API_KEY meta-data. This is used to specify the API key.
The template also adds a Google Play Services dependency to build.gradle. This dependency exposes the Google Maps and Location Services APIs to the application.
compile 'com.google.android.gms:play-services:VERSION_HERE'
When the build is complete, run the app to see what you have:
mapping_start_project_6_run_1
All you have is a blank screen with no map; you haven’t yet set up the API key for the Google Map. You’ll do that next.
Note: If you’re using an emulator, the emulator’s installed version will have to satisfy the version of Google Play Services required in your build.gradle file. If you see a message that you need to update the emulator’s Google Play Services version, you can either download the latest Google APIs using your Android Studio SDK Manager and install on your Virtual Device, or lower the version in your gradle dependency.

Using the Google Maps APIs

To use any of the Google Maps APIs, you need to create an API key and enable any required APIs from the developer console. If you don’t already have a Google account, create one now — it’s free!

Creating API Keys

Open res/values/google_maps_api.xml. You will see the following:
mapping_start_project_7_create_api_1
Now copy and paste the link shown above into your browser.
On the Enable an API page, select Create a project and click Continue.
mapping_start_project_8_create_api_2
On the next screen, click the Create API key button to continue.
mapping_start_project_9_create_api_3
When that’s done, copy the API key shown in the API key created dialog and click Close.
mapping_start_project_10_create_api_4
Head back to google_maps_api.xml, replace the value of google_maps_key key with the copied API key.
Build and run again. You should see a map with a red marker on the screen.
mapping_start_project_11_create_api_5
Go back to the developer console and enable the Google Places API for Android. You will be using this later on to search for a place.

Setting up Play Services Connection

Before adding any Java code, you’ll need to configure Android Studio to automatically insert import statements to save you from having to add each one manually.
Go to Android Studio > Preferences > Editor > General > Auto Import, select the Add unambiguous imports on the fly and the Show import popup checkboxes, and click OK.
auto_import_android_studio
Open MapsActivity.java and have MapsActivity implement the following interfaces:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, GoogleMap.OnMarkerClickListener, LocationListener
The import for LocationListener is ambiguous, so tell Android Studio to import it from Google Mobile Services:
import com.google.android.gms.location.LocationListener;
Here’s what each interface does:
  • GoogleApiClient.ConnectionCallbacks provides callbacks that are triggered when the client is connected (onConnected()) or temporarily disconnected (onConnectionSuspended()) from the service.
  • GoogleApiClient.OnConnectionFailedListener provides a callback method (onConnectionFailed()) that is triggered when an attempt to connect the client to the service results in a failure.
  • GoogleMap.OnMarkerClickListener defines the onMarkerClick() which is called when a marker is clicked or tapped.
  • LocationListener defines the onLocationChanged() which is called when a user’s location changes. This method is only called if the LocationListener has been registered.
Now you need to implement all methods declared in each of the interfaces added above. To do this, follow the steps below:
  1. Place the cursor anywhere on the class declaration and click on the red light bulb icon that appears above the class declaration.
  2. Select Implement methods from the options that appear.
  3. implement_methods_android_studio
  4. On the Select Methods to implement dialog, click OK.
  5. select_methods_to_implement
This will add implementations of all the methods shown in the dialog to the class.
To connect to any Google API provided by the Google Play Services library, you need to create an instance of the GoogleApiClient first.
Add the following field in MapsActivity.java:
private GoogleApiClient mGoogleApiClient;
Add the following lines of code to onCreate(),
// 1
if (mGoogleApiClient == null) {
  mGoogleApiClient = new GoogleApiClient.Builder(this)
      .addConnectionCallbacks(this)
      .addOnConnectionFailedListener(this)
      .addApi(LocationServices.API)
      .build();
}
Add the following methods:
@Override
protected void onStart() {
  super.onStart();
  // 2
  mGoogleApiClient.connect();
}
 
@Override
protected void onStop() {
  super.onStop();
  // 3
  if( mGoogleApiClient != null && mGoogleApiClient.isConnected() ) {
    mGoogleApiClient.disconnect();
  }
}
Here’s what’s going on above:
  1. Instantiates the mGoogleApiClient field if it’s null.
  2. Initiates a background connection of the client to Google Play services.
  3. Closes the connection to Google Play services if the client is not null and is connected.
Add the following code to onMapReady():
mMap.getUiSettings().setZoomControlsEnabled(true); 
mMap.setOnMarkerClickListener(this);
Here you enable the zoom controls on the map and declare MapsActivity as the callback triggered when the user clicks a marker on this map.
Now click the marker on the map near Sydney, and you’ll see the title text appear:
google_maps_api_marker
Enter a different set of latitude and longitude values and you’ll see the marker move to your chosen location.
Add the following code to set a marker at New York City with the title “My Favorite City”:
LatLng myPlace = new LatLng(40.73, -73.99);  // this is New York 
mMap.addMarker(new MarkerOptions().position(myPlace).title("My Favorite City"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(myPlace));
Build and run.
google_maps_api_nyc
Notice the map automatically centered the marker on the screen; moveCamera() does this for you. However, the zoom level of the map isn’t right, as it’s fully zoomed out.
Modify moveCamera() as shown below:
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(myPlace, 12));
Zoom level 0 corresponds to the fully zoomed-out world view. Most areas support zoom levels up to 20, while more remote areas only support zoom levels up to 13. A zoom level of 12 is a nice in-between value that shows enough detail without getting crazy-close.
Build and run to view your progress so far.
show_place_marker

User Permissions

Your app needs the ACCESS_FINE_LOCATION permission for getting the user’s location details; you’ve already included this in AndroidManifest.xml.
Starting with Android 6.0, user permissions are handled a little differently than before. You don’t request permission during the installation of your app; rather, you request them at run time when the permission is actually required.
Permissions are classified into two categories: normal and dangerous categories. Permissions that belong to the dangerous category require run time permission from the user. Permissions that request access to the user’s private information such as the user’s CONTACTS, CALENDAR, LOCATION etc. are categorised as dangerous permissions.
Open MapsActivity.java and add the following field:
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
Create a new method called setUpMap() as follows.
private void setUpMap() {
  if (ActivityCompat.checkSelfPermission(this,
    android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]
      {android.Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);  
    return;
  }
}
The code above checks if the app has been granted the ACCESS_FINE_LOCATION permission. If it hasn’t, then request it from the user.
Call setUpMap() inside the onConnected() method as below:
@Override
public void onConnected(@Nullable Bundle bundle) {
  setUpMap();
}
Compile and run; click “Allow” to grant permission.
grant_location_permissions
Note: A thorough discussion of user permissions is beyond the scope of this tutorial, but check out this document on requesting permissions at run time.

Getting Current Location

One of the most common uses for location services is finding the user’s current location. You do this by requesting the last known location of the user’s device from the Google Play services location APIs.
In MapsActivity.java, add the following new field:
private Location mLastLocation;
Next, add the code below to the bottom of setUpMap():
// 1
mMap.setMyLocationEnabled(true);
 
// 2
LocationAvailability locationAvailability =
    LocationServices.FusedLocationApi.getLocationAvailability(mGoogleApiClient);
if (null != locationAvailability && locationAvailability.isLocationAvailable()) {
  // 3
  mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
  // 4
  if (mLastLocation != null) { 
    LatLng currentLocation = new LatLng(mLastLocation.getLatitude(), mLastLocation
        .getLongitude());
    mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLocation, 12));
  }
}
Taking each commented section in turn:
  1. setMyLocationEnabled enables the my-location layer which draws a light blue dot on the user’s location. It also adds a button to the map that, when tapped, centers the map on the user’s location.
  2. getLocationAvailability determines the availability of location data on the device.
  3. getLastLocation gives you the most recent location currently available
  4. If you were able to retrieve the the most recent location, then move the camera to the user’s current location.
Build and run to view your progress so far. You’ll see a light blue dot on the user’s location:
users_location_GoogleMapsAPI

Emulator Testing

It’s best to use a real Android device to test a map application. If for some reason, you need to test from an emulator, you can do so by mocking location data in the emulator.
One way to do this is by using the emulator’s extended controls. Here’s how you’d do that:
  1. Start the emulator. On the right hand panel, click the more icon () to access the Extended Controls.
  2. Screen Shot 2016-11-24 at 9.09.43 AM
  3. Select the Location item on the left hand side of the Extended Controls dialog.
  4. Enter the latitude and longitude values in the specified fields and click Send.
using_emulator_for_testing_location

Markers

As you may have noticed from the last run, the blue dot on the user’s location is not very prominent. The Android Maps API lets you use a marker object, which is an icon that can be placed at a particular point on the map’s surface.
In MapsActivity.java add the following code.
protected void placeMarkerOnMap(LatLng location) {
  // 1
  MarkerOptions markerOptions = new MarkerOptions().position(location);
  // 2
  mMap.addMarker(markerOptions);
}
  1. Create a MarkerOptions object and sets the user’s current location as the position for the marker
  2. Add the marker to the map
Now replace setUpMap() with the following:
private void setUpMap() {
  if (ActivityCompat.checkSelfPermission(this,
      android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]
        {android.Manifest.permission.ACCESS_FINE_LOCATION},LOCATION_PERMISSION_REQUEST_CODE);
    return;
  }
 
  mMap.setMyLocationEnabled(true);
 
  LocationAvailability locationAvailability =
      LocationServices.FusedLocationApi.getLocationAvailability(mGoogleApiClient);
  if (null != locationAvailability && locationAvailability.isLocationAvailable()) {
    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (mLastLocation != null) {
      LatLng currentLocation = new LatLng(mLastLocation.getLatitude(), mLastLocation
          .getLongitude());
      //add pin at user's location
      placeMarkerOnMap(currentLocation);
      mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLocation, 12));
    }
  }
}
The only change you made to setUpMap() here is adding a call to placeMarkerOnMap() to show the marker.
Build and run to view your progress so far. You should see a pin on the user’s location:
Screen Shot 2016-10-02 at 10.34.13 PM
Don’t like the default Android pins? You can also create a marker with a custom icon as the pin. Go back to placeMarkerOnMap() and add the following line of code after the MarkerOptions instantiation:
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource
    (getResources(), R.mipmap.ic_user_location)));
Download custom pins named ic_user_location from this link and unzip it. Copy all the files to the corresponding mipmap folders of the project as shown below.
Screen Shot 2016-11-24 at 11.01.55 AM
Build and run to view your progress so far. The marker on your location should now be using the ic_user_location icon in the project:
Screen Shot 2016-10-02 at 11.00.18 PM
What if all you want is the default pin but in a different color? Try to figure this out by yourself, and then check the spoiler below if you need more help:

Solution Inside Show




Changing the Map Type

Depending on the functionality of your app, the normal map view might not be detailed enough for you.
The Android Maps API provides different map types to help you out: MAP_TYPE_NORMAL, MAP_TYPE_SATELLITE, MAP_TYPE_TERRAIN, MAP_TYPE_HYBRID
Add the following inside setUpMap() just below the setMyLocationEnabled() call:
mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
GoogleMap.MAP_TYPE_TERRAIN displays a more detailed view of the area, showing changes in elevation:
Screenshot_2016-08-21-04-46-28
Here’s what the other types look like:
GoogleMap.MAP_TYPE_SATELLITE displays a satellite view of an area with no labels.
Screenshot_2016-08-21-04-44-07
GoogleMap.MAP_TYPE_HYBRID displays a combination of the satellite and normal mode
Screenshot_2016-08-21-04-48-25
GoogleMap.MAP_TYPE_NORMAL displays a typical road map with labels. This is default type.
Screenshot_2016-08-21-04-42-54

Implementing Geocoding

Now that you have the user’s location, it would be nice if you could show the address of that location when the user clicks on the marker. Google has a class that does exactly that: Geocoder. This takes the coordinates of a location and returns a readable address and vice versa.
Open MapsActivity. Add the following method:
private String getAddress( LatLng latLng ) {
  // 1
  Geocoder geocoder = new Geocoder( this );
  String addressText = "";
  List<Address> addresses = null;
  Address address = null;
  try {
    // 2
    addresses = geocoder.getFromLocation( latLng.latitude, latLng.longitude, 1 );
    // 3
    if (null != addresses && !addresses.isEmpty()) {
      address = addresses.get(0);
      for (int i = 0; i < address.getMaxAddressLineIndex(); i++) {
        addressText += (i == 0)?address.getAddressLine(i):("\n" + address.getAddressLine(i));
      }
    }
  } catch (IOException e ) {
  }
  return addressText;
}
The import for Address is ambiguous, so specify the following import to resolve the issue:
import android.location.Address;
Briefly, here’s what’s going on:
  1. Creates a Geocoder object to turn a latitude and longitude coordinate into an address and vice versa.
  2. Asks the geocoder to get the address from the location passed to the method.
  3. If the response contains any address, then append it to a string and return.
Replace placeMarkerOnMap() with the following.
protected  void placeMarkerOnMap(LatLng location) {
  MarkerOptions markerOptions = new MarkerOptions().position(location);
 
  String titleStr = getAddress(location);  // add these two lines
  markerOptions.title(titleStr);
 
  mMap.addMarker(markerOptions);
}
Here you added a call to getAddress() and added this address as the marker title.
Build and run to view your progress so far. Click on the marker to see the address:
Screen Shot 2016-10-02 at 10.46.45 AM
Click anywhere on the map to dismiss the address.
Notice that when you move locations, the blue dot moves with you, but the marker remains at it’s first location. If you’re using a physical device, try moving around to see this. If you are on emulator, change your coordinates to another location in your emulator control.
The marker doesn’t move because your code does not know that the location has changed. The blue dot is controlled by the Google API, not your code. If you want the marker to follow the blue dot always, you need to receive location updates as a call-back in your code.

Receiving Location Updates

Knowing your user’s location at all times can help you provide a better experience. This section of the tutorial shows you how to continuously receive updates of your user’s location.
To do this, you first have to create a location request.
Open MapsActivity. Now add the following fields:
// 1
private LocationRequest mLocationRequest;
private boolean mLocationUpdateState;
// 2
private static final int REQUEST_CHECK_SETTINGS = 2;
  1. Declare a LocationRequest member variable and a location updated state variable.
  2. REQUEST_CHECK_SETTINGS is used as the request code passed to onActivityResult.
Next add the following:
protected void startLocationUpdates() {
  //1
  if (ActivityCompat.checkSelfPermission(this,
      android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
    ActivityCompat.requestPermissions(this,
               new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
               LOCATION_PERMISSION_REQUEST_CODE);  
    return;
  }
  //2
  LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest,
  this);
}
  1. In startLocationUpdates(), if the ACCESS_FINE_LOCATION permission has not been granted, request it now and return.
  2. If there is permission, request for location updates.
Now add the following method:
// 1
protected void createLocationRequest() {
  mLocationRequest = new LocationRequest();
  // 2
  mLocationRequest.setInterval(10000); 
  // 3
  mLocationRequest.setFastestInterval(5000); 
  mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
 
  LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
      .addLocationRequest(mLocationRequest);
 
  PendingResult<LocationSettingsResult> result =
      LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient,
          builder.build());
 
  result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
    @Override
    public void onResult(@NonNull LocationSettingsResult result) {
      final Status status = result.getStatus();
      switch (status.getStatusCode()) {
        // 4
        case LocationSettingsStatusCodes.SUCCESS: 
          mLocationUpdateState = true;
          startLocationUpdates();
          break;
        // 5
        case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: 
          try {
            status.startResolutionForResult(MapsActivity.this, REQUEST_CHECK_SETTINGS);
          } catch (IntentSender.SendIntentException e) {
          }
          break;
        // 6
        case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: 
          break;
      }
    }
  });
}
The ResultCallback import is ambiguous, so add the following import statement:
import com.google.android.gms.common.api.ResultCallback;
Here’s what’s going on in createLocationRequest():
  1. You create an instance of LocationRequest, add it to an instance of LocationSettingsRequest.Builder and retrieve and handle any changes to be made based on the current state of the user’s location settings.
  2. setInterval() specifies the rate at which your app will like to receive updates.
  3. setFastestInterval() specifies the fastest rate at which the app can handle updates. Setting the fastestInterval rate places a limit on how fast updates will be sent to your app.
  4. Before you start requesting for location updates, you need to check the state of the user’s location settings.
  5. A SUCCESS status means all is well and you can go ahead and initiate a location request.
  6. A RESOLUTION_REQUIRED status means the location settings have some issues which can be fixed. This could be as a result of the user’s location settings turned off. You fix this by showing the user a dialog as shown below:
  7. Screenshot_20160921-065033
  8. A SETTINGS_CHANGE_UNAVAILABLE status means the location settings have some issues that you can’t fix. This could be as a result of the user choosing NEVER on the dialog above.
Now add the following three methods:
// 1
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == REQUEST_CHECK_SETTINGS) {
    if (resultCode == RESULT_OK) {
      mLocationUpdateState = true;
      startLocationUpdates();
    }
  }
}
 
// 2
@Override
protected void onPause() {
  super.onPause();
  LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
 
// 3
@Override
public void onResume() {
  super.onResume();
  if (mGoogleApiClient.isConnected() && !mLocationUpdateState) {
    startLocationUpdates();
  }
}
Here’s what’s going on:
  1. Override FragmentActivity’s onActivityResult() method and start the update request if it has a RESULT_OK result for a REQUEST_CHECK_SETTINGS request.
  2. Override onPause() to stop location update request
  3. Override onResume() to restart the location update request.
Next, add a call to createLocationRequest() to the bottom of onCreate():
createLocationRequest();
Then, add the following lines of code to onConnected():
if (mLocationUpdateState) {
  startLocationUpdates();
}
Here you start location updates if user’s location settings are turned on.
Next add these lines of code to onLocationChanged():
mLastLocation = location;
if (null != mLastLocation) {
  placeMarkerOnMap(new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()));
}
Here you update mLastLocation with the new location and update the map with the new location coordinates.
Your app is now set to receive location updates. When you change your location, the map will update with a new marker showing your new location. Note that the markers are still clickable to get the address as before.
Build and run. Play around with the app to view the changes:
Screen Shot 2016-10-03 at 12.19.52 AM

Place Search

Since this app is supposed to be a guide, a user should be able to search for places of interest to them, right?
That’s where the Google Places API comes in; it provides your app the functionality to search for millions of institutions and places of interest. It’s Android Library provides a number of cool functionalities, one of them being the Place Picker, which is a UI widget that lets you provide a place search functionality with very few lines of code. Too good to be true? Try it!
Once again, open MapsActivity.
Add this field:
private static final int PLACE_PICKER_REQUEST = 3;
Now add the following method:
private void loadPlacePicker() {
  PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
 
  try {
    startActivityForResult(builder.build(MapsActivity.this), PLACE_PICKER_REQUEST);
  } catch(GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException e) {
      e.printStackTrace();
  }
}
This method creates a new builder for an intent to start the Place Picker UI and then starts the PlacePicker intent.
Now add the following lines of code to onActivityResult():
if (requestCode == PLACE_PICKER_REQUEST) {
  if (resultCode == RESULT_OK) {
    Place place = PlacePicker.getPlace(this, data);
    String addressText = place.getName().toString();
    addressText += "\n" + place.getAddress().toString();
 
    placeMarkerOnMap(place.getLatLng());
  }
}
Here you retrieve details about the selected place if it has a RESULT_OK result for a PLACE_PICKER_REQUEST request, and then place a marker on that position on the map.
You are almost ready to try out the place search — you just need to call loadPlacePicker() inside the code.
You’ll create a floating action button (FAB) at the bottom-right of the map to trigger this method. FAB requires CoordinatorLayout which is part of the design support library.
First open build.gradle for the app and add the Android support design library as a dependency:
dependencies {
  ...
  compile 'com.android.support:design:24.1.1'
}
Note: As usual, if you are using a newer Android SDK version, you may need to update the version of this dependency as well so they match.
Then replace the contents of res > layout > activity_maps.xml with the following lines of code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    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"
    android:fitsSystemWindows="true">
 
    <fragment
        android:id="@+id/map"
        class="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
 
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:src="@android:drawable/ic_menu_search"/>
 
</android.support.design.widget.CoordinatorLayout>
You were using a fragment element for map earlier; you’ve kept that and added a floating action button.
In MapsActivity, add the following lines of code to onCreate():
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    loadPlacePicker();
  }
});
Build and run. Now when you click the search button at the bottom of the map the place picker will load:
placepickerdemo4

Where to Go From Here?

You can download the final project from this tutorial here.
This Google Maps API tutorial only brushed the surface of what you can do with the Google Maps APIs. The official Google documentation has much more about web services and and the Android API here.
You can also check out the developer page on other ways to customize the marker. User permission checks for run-time permissions need a better implementation than what you’ve done in this Google Maps API tutorial; the docs also have some great information about more advanced permission granting here.
Check out the developer pages for extensive reading on the Google Places API for Android, receiving location updates and mocking location data via the emulator’s extended controls.
If you have any questions or comments, please feel free to join the forum discussion below!

Harry

Author & Editor

A technology enthusiast and addictive blogger who likes to hacking tricks and wish to be the best White Hacket Hacker of the World.

0 comments:

Post a Comment

Note: only a member of this blog may post a comment.