diff --git a/docs/html/training/location/receive-location-updates.jd b/docs/html/training/location/receive-location-updates.jd index e6e8c51a50787..208dc1799faf3 100644 --- a/docs/html/training/location/receive-location-updates.jd +++ b/docs/html/training/location/receive-location-updates.jd @@ -1,612 +1,417 @@ page.title=Receiving Location Updates trainingnavtop=true @jd:body +
-
+ -
-
+

If your app can continuously track location, it can deliver more relevant + information to the user. For example, if your app helps the user find their + way while walking or driving, or if your app tracks the location of assets, it + needs to get the location of the device at regular intervals. As well as the + geographical location (latitude and longitude), you may want to give the user + further information such as the bearing (horizontal direction of travel), + altitude, or velocity of the device. This information, and more, is available + in the {@link android.location.Location} object that your app can retrieve + from the + fused + location provider.

+ +

While you can get a device's location with + {@code getLastLocation()}, + as illustrated in the lesson on + Getting the Last Known Location, + a more direct approach is to request periodic updates from the fused location + provider. In response, the API updates your app periodically with the best + available location, based on the currently-available location providers such + as WiFi and GPS (Global Positioning System). The accuracy of the location is + determined by the providers, the location permissions you've requested, and + the options you set in the location request.

+ +

This lesson shows you how to request regular updates about a device's + location using the + {@code requestLocationUpdates()} + method in the fused location provider. + +

Connect to Location Services

+ +

Location services for apps are provided through Google Play services and the + fused location provider. In order to use these services, you connect your app + using the Google API Client and then request location updates. For details on + connecting with the + {@code GoogleApiClient}, + follow the instructions in + Getting the Last Known Location, including + requesting the current location.

+ +

The last known location of the device provides a handy base from which to + start, ensuring that the app has a known location before starting the + periodic location updates. The lesson on + Getting the Last Known Location shows you + how to get the last known location by calling + {@code getLastLocation()}. + The snippets in the following sections assume that your app has already + retrieved the last known location and stored it as a + {@link android.location.Location} object in the global variable + {@code mCurrentLocation}.

+ +

Apps that use location services must request location permissions. In this + lesson you require fine location detection, so that your app can get as + precise a location as possible from the available location providers. Request + this permission with the + {@code uses-permission} element in your app manifest, as shown in the + following example:

-

- If your app does navigation or tracking, you probably want to get the user's - location at regular intervals. While you can do this with -LocationClient.getLastLocation(), - a more direct approach is to request periodic updates from Location Services. In - response, Location Services automatically updates your app with the best available location, - based on the currently-available location providers such as WiFi and GPS. -

-

- To get periodic location updates from Location Services, you send a request using a location - client. Depending on the form of the request, Location Services either invokes a callback - method and passes in a {@link android.location.Location} object, or issues an - {@link android.content.Intent} that contains the location in its extended data. The accuracy and - frequency of the updates are affected by the location permissions you've requested and the - parameters you pass to Location Services with the request. -

- -

Specify App Permissions

-

- 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 affects the accuracy of the location updates you receive. - For example, If you request only coarse location permission, Location Services obfuscates the - updated location to an accuracy that's roughly equivalent to a city block. -

-

- 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}. -

-

- For example, to add the coarse location permission to your manifest, insert the following as a - child element of - the -<manifest> - element: -

-<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-
- -

Check for Google Play Services

-

- 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 -GooglePlayServicesUtil.isGooglePlayServicesAvailable(), - which returns one of the - integer result codes listed in the API reference documentation. If you encounter an error, - call -GooglePlayServicesUtil.getErrorDialog() - 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()} +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.gms.location.sample.locationupdates" > -

-

- Note: To make your app compatible with - platform version 1.6 and later, the activity that displays the - {@link android.support.v4.app.DialogFragment} must subclass - {@link android.support.v4.app.FragmentActivity} instead of {@link android.app.Activity}. Using - {@link android.support.v4.app.FragmentActivity} also allows you to call - {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager - getSupportFragmentManager()} to display the {@link android.support.v4.app.DialogFragment}. -

-

- 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: -

-
-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
-        } else {
-            // Get the error code
-            int errorCode = connectionResult.getErrorCode();
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    errorCode,
-                    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");
-            }
-        }
-    }
-    ...
-}
+  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+</manifest>
 
-

- Snippets in the following sections call this method to verify that Google Play services is - available. -

- -

Define Location Services Callbacks

-

- Before you request location updates, you must first implement the interfaces that Location - Services uses to communicate connection status to your app: -

+ +

Set Up a Location Request

+ +

To store parameters for requests to the fused location provider, create a + {@code LocationRequest}. + The parameters determine the levels of accuracy requested. For details of all + the options available in the location request, see the + {@code LocationRequest} + class reference. This lesson sets the update interval, fastest update + interval, and priority, as described below:

+
-
-ConnectionCallbacks -
-
- Specifies methods that Location Services calls when a location client is connected or - disconnected. -
-
-OnConnectionFailedListener -
-
- 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. -
+
+ Update interval +
+
+ {@code setInterval()} + - This method sets the rate in milliseconds at which your app prefers to + receive location updates. Note that the location updates may be faster than + this rate if another app is receiving updates at a faster rate, or slower + than this rate, or there may be no updates at all (if the device has no + connectivity, for example). +
+
+ Fastest update interval +
+
+ {@code setFastestInterval()} + - This method sets the fastest rate in milliseconds at which + your app can handle location updates. You need to set this rate because + other apps also affect the rate at which updates are sent. The Google Play + services location APIs send out updates at the fastest rate that any app + has requested with + {@code setInterval()}. + If this rate is faster + than your app can handle, you may encounter problems with UI flicker or data + overflow. To prevent this, call + {@code setFastestInterval()} + to set an upper limit to the update rate. +
+
Priority
+
+

+ {@code setPriority()} + - This method sets the priority of the request, which gives the Google Play + services location services a strong hint about which location sources to use. + The following values are supported:

+ +
-

- The following snippet shows how to specify the interfaces and define the methods: -

+ +

Create the location request and set the parameters as shown in this + code sample:

+
-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());
-        }
-    }
-    ...
+protected void createLocationRequest() {
+    LocationRequest mLocationRequest = new LocationRequest();
+    mLocationRequest.setInterval(10000);
+    mLocationRequest.setFastestInterval(5000);
+    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
 }
 
-

Define the location update callback

-

- Location Services sends location updates to your app either as an {@link android.content.Intent} - or as an argument passed to a callback method you define. This lesson shows you how to get the - update using a callback method, because that pattern works best for most use cases. If you want - to receive updates in the form of an {@link android.content.Intent}, read the lesson - Recognizing the User's Current Activity, which - presents a similar pattern. -

-

- The callback method that Location Services invokes to send a location update to your app is - specified in the -LocationListener - interface, in the method -onLocationChanged(). - The incoming argument is a {@link android.location.Location} object containing the location's - latitude and longitude. The following snippet shows how to specify the interface and define - the method: -

+ +

The priority of + {@code PRIORITY_HIGH_ACCURACY}, + combined with the + {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} + permission setting that you've defined in the app manifest, and a fast update + interval of 5000 milliseconds (5 seconds), causes the fused location + provider to return location updates that are accurate to within a few feet. + This approach is appropriate for mapping apps that display the location in + real time.

+ +

Performance hint: If your app accesses the + network or does other long-running work after receiving a location update, + adjust the fastest interval to a slower value. This adjustment prevents your + app from receiving updates it can't use. Once the long-running work is done, + set the fastest interval back to a fast value.

+ +

Request Location Updates

+ +

Now that you've set up a location request containing your app's requirements + for the location updates, you can start the regular updates by calling + {@code requestLocationUpdates()}. + Do this in the + {@code onConnected()} + callback provided by Google API Client, which is called when the client is + ready.

+ +

Depending on the form of the request, the fused location provider either + invokes the + {@code LocationListener.onLocationChanged()} + callback method and passes it a {@link android.location.Location} object, or + issues a + {@code PendingIntent} + that contains the location in its extended data. The accuracy and frequency of + the updates are affected by the location permissions you've requested and the + options you set in the location request object.

+ +

This lesson shows you how to get the update using the + {@code LocationListener} + callback approach. Call + {@code requestLocationUpdates()}, + passing it your instance of the + {@code GoogleApiClient}, + the + {@code LocationRequest} + object, + and a {@code LocationListener}. + Define a {@code startLocationUpdates()} method, called from the + {@code onConnected()} + callback, as shown in the following code sample:

+
-public class MainActivity extends FragmentActivity implements
-        GooglePlayServicesClient.ConnectionCallbacks,
-        GooglePlayServicesClient.OnConnectionFailedListener,
-        LocationListener {
+@Override
+public void onConnected(Bundle connectionHint) {
+    ...
+    if (mRequestingLocationUpdates) {
+        startLocationUpdates();
+    }
+}
+
+protected void startLocationUpdates() {
+    LocationServices.FusedLocationApi.requestLocationUpdates(
+            mGoogleApiClient, mLocationRequest, this);
+}
+
+ +

Notice that the above code snippet refers to a boolean flag, + {@code mRequestingLocationUpdates}, used to track whether the user has + turned location updates on or off. For more about retaining the value of this + flag across instances of the activity, see + Save the State of the Activity. + +

Define the Location Update Callback

+ +

The fused location provider invokes the + {@code LocationListener.onLocationChanged()} + callback method. The incoming argument is a {@link android.location.Location} + object containing the location's latitude and longitude. The following snippet + shows how to implement the + {@code LocationListener} + interface and define the method, then get the timestamp of the location update + and display the latitude, longitude and timestamp on your app's user + interface:

+ +
+public class MainActivity extends ActionBarActivity implements
+        ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
     ...
-    // Define the callback method that receives location updates
     @Override
     public void onLocationChanged(Location location) {
-        // Report to the UI that the location was updated
-        String msg = "Updated Location: " +
-                Double.toString(location.getLatitude()) + "," +
-                Double.toString(location.getLongitude());
-        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+        mCurrentLocation = location;
+        mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
+        updateUI();
     }
-    ...
-}
-
-

- Now that you have the callbacks prepared, you can set up the request for location updates. - The first step is to specify the parameters that control the updates. -

- -

Specify Update Parameters

-

- Location Services allows you to control the interval between updates and the location accuracy - you want, by setting the values in a -LocationRequest - object and then sending this object as part of your request to start updates. -

-

- First, set the following interval parameters: -

-
-
- Update interval -
-
- Set by -LocationRequest.setInterval(). - This method sets the rate in milliseconds at which your app prefers to receive location - updates. If no other apps are receiving updates from Location Services, your app will - receive updates at this rate. -
-
- Fastest update interval -
-
- Set by -LocationRequest.setFastestInterval(). - This method sets the fastest rate in milliseconds at which your app can handle - location updates. You need to set this rate because other apps also affect the rate - at which updates are sent. Location Services sends out updates at the fastest rate that any - app requested by calling -LocationRequest.setInterval(). - If this rate is faster than your app can handle, you may encounter problems with UI flicker - or data overflow. To prevent this, call -LocationRequest.setFastestInterval() - to set an upper limit to the update rate. -

- Calling -LocationRequest.setFastestInterval() - also helps to save power. When you request a preferred update rate by calling -LocationRequest.setInterval(), - and a maximum rate by calling -LocationRequest.setFastestInterval(), - then your app gets the same update rate as the fastest rate in the system. If other - apps have requested a faster rate, you get the benefit of a faster rate. If no other - apps have a faster rate request outstanding, your app receives updates at the rate you specified - with -LocationRequest.setInterval(). -

-
-
-

- Next, set the accuracy parameter. In a foreground app, you need constant location updates with - high accuracy, so use the setting -LocationRequest.PRIORITY_HIGH_ACCURACY. -

-

- The following snippet shows how to set the update interval and accuracy in - {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}: -

-
-public class MainActivity extends FragmentActivity implements
-        GooglePlayServicesClient.ConnectionCallbacks,
-        GooglePlayServicesClient.OnConnectionFailedListener,
-        LocationListener {
-    ...
-    // Global constants
-    ...
-    // Milliseconds per second
-    private static final int MILLISECONDS_PER_SECOND = 1000;
-    // Update frequency in seconds
-    public static final int UPDATE_INTERVAL_IN_SECONDS = 5;
-    // Update frequency in milliseconds
-    private static final long UPDATE_INTERVAL =
-            MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
-    // The fastest update frequency, in seconds
-    private static final int FASTEST_INTERVAL_IN_SECONDS = 1;
-    // A fast frequency ceiling in milliseconds
-    private static final long FASTEST_INTERVAL =
-            MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
-    ...
-    // Define an object that holds accuracy and frequency parameters
-    LocationRequest mLocationRequest;
-    ...
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        // Create the LocationRequest object
-        mLocationRequest = LocationRequest.create();
-        // Use high accuracy
-        mLocationRequest.setPriority(
-                LocationRequest.PRIORITY_HIGH_ACCURACY);
-        // Set the update interval to 5 seconds
-        mLocationRequest.setInterval(UPDATE_INTERVAL);
-        // Set the fastest update interval to 1 second
-        mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
-        ...
-    }
-    ...
-}
-
-

- Note: If your app accesses the network or does other long-running work after - receiving a location update, adjust the fastest interval to a slower value. This prevents your - app from receiving updates it can't use. Once the long-running work is done, set the fastest - interval back to a fast value. -

- -

Start Location Updates

-

- To send the request for location updates, create a location client in - {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}, then connect it and make - the request by calling -requestLocationUpdates(). - Since your client must be connected for your app to receive updates, you should - connect the client in - {@link android.support.v4.app.FragmentActivity#onStart onStart()}. This ensures that you always - have a valid, connected client while your app is visible. Since you need a connection before you - can request updates, make the update request in -ConnectionCallbacks.onConnected() -

-

- Remember that the user may want to turn off location updates for various reasons. You should - provide a way for the user to do this, and you should ensure that you don't start updates in - {@link android.support.v4.app.FragmentActivity#onStart onStart()} if updates were previously - turned off. To track the user's preference, store it in your app's - {@link android.content.SharedPreferences} in - {@link android.support.v4.app.FragmentActivity#onPause onPause()} and retrieve it in - {@link android.support.v4.app.FragmentActivity#onResume onResume()}. -

-

- The following snippet shows how to set up the client in - {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}, and how to connect it - and request updates in {@link android.support.v4.app.FragmentActivity#onStart onStart()}: -

-
-public class MainActivity extends FragmentActivity implements
-        GooglePlayServicesClient.ConnectionCallbacks,
-        GooglePlayServicesClient.OnConnectionFailedListener,
-        LocationListener {
-    ...
-    // Global variables
-    ...
-    LocationClient mLocationClient;
-    boolean mUpdatesRequested;
-    ...
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        ...
-        // Open the shared preferences
-        mPrefs = getSharedPreferences("SharedPreferences",
-                Context.MODE_PRIVATE);
-        // Get a SharedPreferences editor
-        mEditor = mPrefs.edit();
-        /*
-         * Create a new location client, using the enclosing class to
-         * handle callbacks.
-         */
-        mLocationClient = new LocationClient(this, this, this);
-        // Start with updates turned off
-        mUpdatesRequested = false;
-        ...
-    }
-    ...
-    @Override
-    protected void onPause() {
-        // Save the current setting for updates
-        mEditor.putBoolean("KEY_UPDATES_ON", mUpdatesRequested);
-        mEditor.commit();
-        super.onPause();
-    }
-    ...
-    @Override
-    protected void onStart() {
-        ...
-        mLocationClient.connect();
-    }
-    ...
-    @Override
-    protected void onResume() {
-        /*
-         * Get any previous setting for location updates
-         * Gets "false" if an error occurs
-         */
-        if (mPrefs.contains("KEY_UPDATES_ON")) {
-            mUpdatesRequested =
-                    mPrefs.getBoolean("KEY_UPDATES_ON", false);
 
-        // Otherwise, turn off location updates
-        } else {
-            mEditor.putBoolean("KEY_UPDATES_ON", false);
-            mEditor.commit();
-        }
+    private void updateUI() {
+        mLatitudeTextView.setText(String.valueOf(mCurrentLocation.getLatitude()));
+        mLongitudeTextView.setText(String.valueOf(mCurrentLocation.getLongitude()));
+        mLastUpdateTimeTextView.setText(mLastUpdateTime);
     }
-    ...
-    /*
-     * 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();
-        // If already requested, start periodic updates
-        if (mUpdatesRequested) {
-            mLocationClient.requestLocationUpdates(mLocationRequest, this);
-        }
-    }
-    ...
 }
 
-

- For more information about saving preferences, read -Saving Key-Value Sets. -

- -

Stop Location Updates

-

- To stop location updates, save the state of the update flag in - {@link android.support.v4.app.FragmentActivity#onPause onPause()}, and stop updates in - {@link android.support.v4.app.FragmentActivity#onStop onStop()} by calling -removeLocationUpdates(LocationListener). - For example: -

+ +

Stop Location Updates

+ +

Consider whether you want to stop the location updates when the activity is + no longer in focus, such as when the user switches to another app or to a + different activity in the same app. This can be handy to reduce power + consumption, provided the app doesn't need to collect information even when + it's running in the background. This section shows how you can stop the + updates in the activity's + {@link android.app.Activity#onPause onPause()} method.

+ +

To stop location updates, call + {@code removeLocationUpdates()}, + passing it your instance of the + {@code GoogleApiClient} + object and a + {@code LocationListener}, + as shown in the following code sample:

+
-public class MainActivity extends FragmentActivity implements
-        GooglePlayServicesClient.ConnectionCallbacks,
-        GooglePlayServicesClient.OnConnectionFailedListener,
-        LocationListener {
-    ...
-    /*
-     * Called when the Activity is no longer visible at all.
-     * Stop updates and disconnect.
-     */
-    @Override
-    protected void onStop() {
-        // If the client is connected
-        if (mLocationClient.isConnected()) {
-            /*
-             * Remove location updates for a listener.
-             * The current Activity is the listener, so
-             * the argument is "this".
-             */
-            removeLocationUpdates(this);
-        }
-        /*
-         * After disconnect() is called, the client is
-         * considered "dead".
-         */
-        mLocationClient.disconnect();
-        super.onStop();
-    }
-    ...
+@Override
+protected void onPause() {
+    super.onPause();
+    stopLocationUpdates();
+}
+
+protected void stopLocationUpdates() {
+    LocationServices.FusedLocationApi.removeLocationUpdates(
+            mGoogleApiClient, this);
 }
 
-

- You now have the basic structure of an app that requests and receives periodic location updates. - You can combine the features described in this lesson with the geofencing, activity recognition, - or reverse geocoding features described in other lessons in this class. -

-

- The next lesson, Displaying a Location Address, shows you how - to use the current location to display the current street address. -

+ +

Use a boolean, {@code mRequestingLocationUpdates}, to track + whether location updates are currently turned on. In the activity's + {@link android.app.Activity#onResume onResume()} method, check + whether location updates are currently active, and activate them if not:

+ +
+@Override
+public void onResume() {
+    super.onResume();
+    if (mGoogleApiClient.isConnected() && !mRequestingLocationUpdates) {
+        startLocationUpdates();
+    }
+}
+
+ +

Save the State of the Activity

+ +

A change to the device's configuration, such as a change in screen + orientation or language, can cause the current activity to be destroyed. Your + app must therefore store any information it needs to recreate the activity. + One way to do this is via an instance state stored in a + {@link android.os.Bundle} object.

+ +

The following code sample shows how to use the activity's + {@code onSaveInstanceState()} + callback to save the instance state:

+ +
+public void onSaveInstanceState(Bundle savedInstanceState) {
+    savedInstanceState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY,
+            mRequestingLocationUpdates);
+    savedInstanceState.putParcelable(LOCATION_KEY, mCurrentLocation);
+    savedInstanceState.putString(LAST_UPDATED_TIME_STRING_KEY, mLastUpdateTime);
+    super.onSaveInstanceState(savedInstanceState);
+}
+
+ +

Define an {@code updateValuesFromBundle()} method to restore + the saved values from the previous instance of the activity, if they're + available. Call the method from the activity's + {@link android.app.Activity#onCreate onCreate()} method, as shown in the + following code sample:

+ +
+@Override
+public void onCreate(Bundle savedInstanceState) {
+    ...
+    updateValuesFromBundle(savedInstanceState);
+}
+
+private void updateValuesFromBundle(Bundle savedInstanceState) {
+    if (savedInstanceState != null) {
+        // Update the value of mRequestingLocationUpdates from the Bundle, and
+        // make sure that the Start Updates and Stop Updates buttons are
+        // correctly enabled or disabled.
+        if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
+            mRequestingLocationUpdates = savedInstanceState.getBoolean(
+                    REQUESTING_LOCATION_UPDATES_KEY);
+            setButtonsEnabledState();
+        }
+
+        // Update the value of mCurrentLocation from the Bundle and update the
+        // UI to show the correct latitude and longitude.
+        if (savedInstanceState.keySet().contains(LOCATION_KEY)) {
+            // Since LOCATION_KEY was found in the Bundle, we can be sure that
+            // mCurrentLocationis not null.
+            mCurrentLocation = savedInstanceState.getParcelable(LOCATION_KEY);
+        }
+
+        // Update the value of mLastUpdateTime from the Bundle and update the UI.
+        if (savedInstanceState.keySet().contains(LAST_UPDATED_TIME_STRING_KEY)) {
+            mLastUpdateTime = savedInstanceState.getString(
+                    LAST_UPDATED_TIME_STRING_KEY);
+        }
+        updateUI();
+    }
+}
+
+ +

For more about saving instance state, see the + Android + Activity class reference.

+ +

Note: For a more persistent storage, you can + store the user's preferences in your app's + {@link android.content.SharedPreferences}. Set the shared preference in + your activity's {@link android.app.Activity#onPause onPause()} method, and + retrieve the preference in {@link android.app.Activity#onResume onResume()}. + For more information about saving preferences, read + Saving + Key-Value Sets.

+ +

The next lesson, + Displaying a Location Address, shows + you how to display the street address for a given location.