page.title=Retrieving the Current Location trainingnavtop=true @jd:body <div id="tb-wrapper"> <div id="tb"> <h2>This lesson teaches you to</h2> <ol> <li><a href="#AppPermissions">Specify App Permissions</a></li> <li><a href="#CheckServices">Check for Google Play services</a></li> <li><a href="#DefineCallbacks">Define Location Services Callbacks</a></li> <li><a href="#ConnectClient">Connect the Location Client</a></li> <li><a href="#GetLocation">Get the Current Location</a></li> </ol> <h2>You should also read</h2> <ul> <li> <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a> </li> </ul> <h2>Try it out</h2> <div class="download-box"> <a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download the sample</a> <p class="filename">LocationUpdates.zip</p> </div> </div> </div> <p> Location Services automatically maintains the user's current location, so all your app has to do is retrieve it as needed. The location's accuracy is based on the location permissions you've requested and location sensors that are currently active for the device. <p> Location Services sends the current location to your app through a location client, which is an instance of the Location Services class <code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html">LocationClient</a></code>. All requests for location information go through this client. </p> <p class="note"> <strong>Note:</strong> Before you start the lesson, be sure that your development environment and test device are set up correctly. To learn more about this, read the <a href="{@docRoot}google/play-services/setup.html">Setup</a> section in the Google Play services guide. </p> <!-- Specify App Permissions --> <h2 id="AppPermissions">Specify App Permissions</h2> <p> Apps that use Location Services must request location permissions. Android has two location permissions: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} and {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. The permission you choose controls the accuracy of the current location. If you request only coarse location permission, Location Services obfuscates the returned location to an accuracy that's roughly equivalent to a city block. </p> <p> Requesting {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} implies a request for {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}. </p> <p> For example, to add {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}, insert the following as a child element of the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> element: </p> <pre> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> </pre> <!-- Check for Google Play Services --> <h2 id="CheckServices">Check for Google Play Services</h2> <p> Location Services is part of the Google Play services APK. Since it's hard to anticipate the state of the user's device, you should always check that the APK is installed before you attempt to connect to Location Services. To check that the APK is installed, call <code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>, which returns one of the integer result codes listed in the reference documentation for <code><a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a></code>. If you encounter an error, call <code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code> to retrieve localized dialog that prompts users to take the correct action, then display the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the user to correct the problem, in which case Google Play services may send a result back to your activity. To handle this result, override the method {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()}. </p> <p> Since you usually need to check for Google Play services in more than one place in your code, define a method that encapsulates the check, then call the method before each connection attempt. The following snippet contains all of the code required to check for Google Play services: </p> <pre> public class MainActivity extends FragmentActivity { ... // Global constants /* * Define a request code to send to Google Play services * This code is returned in Activity.onActivityResult */ private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; ... // Define a DialogFragment that displays the error dialog public static class ErrorDialogFragment extends DialogFragment { // Global field to contain the error dialog private Dialog mDialog; // Default constructor. Sets the dialog field to null public ErrorDialogFragment() { super(); mDialog = null; } // Set the dialog to display public void setDialog(Dialog dialog) { mDialog = dialog; } // Return a Dialog to the DialogFragment. @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return mDialog; } } ... /* * Handle results returned to the FragmentActivity * by Google Play services */ @Override protected void onActivityResult( int requestCode, int resultCode, Intent data) { // Decide what to do based on the original request code switch (requestCode) { ... case CONNECTION_FAILURE_RESOLUTION_REQUEST : /* * If the result code is Activity.RESULT_OK, try * to connect again */ switch (resultCode) { case Activity.RESULT_OK : /* * Try the request again */ ... break; } ... } } ... private boolean servicesConnected() { // Check that Google Play services is available int resultCode = GooglePlayServicesUtil. isGooglePlayServicesAvailable(this); // If Google Play services is available if (ConnectionResult.SUCCESS == resultCode) { // In debug mode, log the status Log.d("Location Updates", "Google Play services is available."); // Continue return true; // Google Play services was not available for some reason. // resultCode holds the error code. } else { // Get the error dialog from Google Play services Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog( resultCode, this, CONNECTION_FAILURE_RESOLUTION_REQUEST); // If Google Play services can provide an error dialog if (errorDialog != null) { // Create a new DialogFragment for the error dialog ErrorDialogFragment errorFragment = new ErrorDialogFragment(); // Set the dialog in the DialogFragment errorFragment.setDialog(errorDialog); // Show the error dialog in the DialogFragment errorFragment.show(getSupportFragmentManager(), "Location Updates"); } } } ... } </pre> <p> Snippets in the following sections call this method to verify that Google Play services is available. </p> <!-- Define Location Services Callbacks --> <h2 id="DefineCallbacks">Define Location Services Callbacks</h2> <p> To get the current location, create a location client, connect it to Location Services, and then call its <code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code> method. The return value is the best, most recent location, based on the permissions your app requested and the currently-enabled location sensors. <p> <p> Before you create the location client, implement the interfaces that Location Services uses to communicate with your app: </p> <dl> <dt> <code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code> </dt> <dd> Specifies methods that Location Services calls when a location client is connected or disconnected. </dd> <dt> <code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code> </dt> <dd> Specifies a method that Location Services calls if an error occurs while attempting to connect the location client. This method uses the previously-defined {@code showErrorDialog} method to display an error dialog that attempts to fix the problem using Google Play services. </dd> </dl> <p> The following snippet shows how to specify the interfaces and define the methods: </p> <pre> public class MainActivity extends FragmentActivity implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener { ... /* * Called by Location Services when the request to connect the * client finishes successfully. At this point, you can * request the current location or start periodic updates */ @Override public void onConnected(Bundle dataBundle) { // Display the connection status Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show(); } ... /* * Called by Location Services if the connection to the * location client drops because of an error. */ @Override public void onDisconnected() { // Display the connection status Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); } ... /* * Called by Location Services if the attempt to * Location Services fails. */ @Override public void onConnectionFailed(ConnectionResult connectionResult) { /* * Google Play services can resolve some errors it detects. * If the error has a resolution, try sending an Intent to * start a Google Play services activity that can resolve * error. */ if (connectionResult.hasResolution()) { try { // Start an Activity that tries to resolve the error connectionResult.startResolutionForResult( this, CONNECTION_FAILURE_RESOLUTION_REQUEST); /* * Thrown if Google Play services canceled the original * PendingIntent */ } catch (IntentSender.SendIntentException e) { // Log the error e.printStackTrace(); } } else { /* * If no resolution is available, display a dialog to the * user with the error. */ showErrorDialog(connectionResult.getErrorCode()); } } ... } </pre> <!-- Connect the Location Client --> <h2 id="ConnectClient">Connect the Location Client</h2> <p> Now that the callback methods are in place, create the location client and connect it to Location Services. </p> <p> You should create the location client in {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}, then connect it in {@link android.support.v4.app.FragmentActivity#onStart onStart()}, so that Location Services maintains the current location while your activity is fully visible. Disconnect the client in {@link android.support.v4.app.FragmentActivity#onStop onStop()}, so that when your app is not visible, Location Services is not maintaining the current location. Following this pattern of connection and disconnection helps save battery power. For example: </p> <p class="note"> <strong>Note:</strong> The current location is only maintained while a location client is connected to Location Service. Assuming that no other apps are connected to Location Services, if you disconnect the client and then sometime later call <code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>, the result may be out of date. </p> <pre> public class MainActivity extends FragmentActivity implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener { ... @Override protected void onCreate(Bundle savedInstanceState) { ... /* * Create a new location client, using the enclosing class to * handle callbacks. */ mLocationClient = new LocationClient(this, this, this); ... } ... /* * Called when the Activity becomes visible. */ @Override protected void onStart() { super.onStart(); // Connect the client. mLocationClient.connect(); } ... /* * Called when the Activity is no longer visible. */ @Override protected void onStop() { // Disconnecting the client invalidates it. mLocationClient.disconnect(); super.onStop(); } ... } </pre> <!-- Get the Current Location --> <h2 id="GetLocation">Get the Current Location</h2> <p> To get the current location, call <code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>. For example: </p> <pre> public class MainActivity extends FragmentActivity implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener { ... // Global variable to hold the current location Location mCurrentLocation; ... mCurrentLocation = mLocationClient.getLastLocation(); ... } </pre> <p> The next lesson, <a href="receive-location-updates.html">Receiving Location Updates</a>, shows you how to receive periodic location updates from Location Services. </p>