am ecf0ac29: am ca23a587: Merge "docs: Updates the request-location-updates lesson in the location APIs training course." into lmp-docs
* commit 'ecf0ac290b5ef1b03e307d591df7be2dfb6a877b':
docs: Updates the request-location-updates lesson in the location APIs training course.
diff --git a/docs/html/training/location/receive-location-updates.jd b/docs/html/training/location/receive-location-updates.jd
index e6e8c51..208dc17 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
+
<div id="tb-wrapper">
-<div id="tb">
+ <div id="tb">
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#Permissions">Request Location Permission</a></li>
- <li><a href="#PlayServices">Check for Google Play Services</a></li>
- <li><a href="#DefineCallbacks">Define Location Services Callbacks</a></li>
- <li><a href="#UpdateParameters">Specify Update Parameters</a></li>
- <li><a href="#StartUpdates">Start Location Updates</a></li>
- <li><a href="#StopUpdates">Stop Location Updates</a></li>
-</ol>
+ <h2>This lesson teaches you how to</h2>
+ <ol>
+ <li><a href="#connect">Connect to Location Services</a></li>
+ <li><a href="#location-request">Set Up a Location Request</a></li>
+ <li><a href="#updates">Request Location Updates</a></li>
+ <li><a href="#callback">Define the Location Update Callback</a></li>
+ <li><a href="#stop-updates">Stop Location Updates</a></li>
+ <li><a href="#save-state">Save the State of the Activity</a></li>
+ </ol>
-<h2>You should also read</h2>
-<ul>
+ <h2>You should also read</h2>
+ <ul>
<li>
- <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>
+ <a href="{@docRoot}google/play-services/setup.html">Setting up Google Play
+ Services</a>
</li>
<li>
- <a href="retrieve-current.html">Retrieving the Current Location</a>
+ <a href="retrieve-current.html">Getting the Last Known Location</a>
</li>
- </ul>
+ </ul>
-<h2>Try it out</h2>
+ <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>
+ <ul>
+ <li>
+ <a href="https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates" class="external-link">LocationUpdates</a>
+ </li>
+ </ul>
+ </div>
</div>
-</div>
-</div>
+<p>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
+ <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">fused
+ location provider</a>.</p>
-<p>
- 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
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">LocationClient.getLastLocation()</a></code>,
- 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.
-</p>
-<p>
- 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.
-</p>
-<!-- Request permission -->
-<h2 id="Permissions">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 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.
-</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 the coarse location permission to your manifest, insert the following as a
- child element of
- the
-<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>
- element:
-</p>
+<p>While you can get a device's location with
+ <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>,
+ as illustrated in the lesson on
+ <a href="retrieve-current.html">Getting the Last Known Location</a>,
+ 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.</p>
+
+<p>This lesson shows you how to request regular updates about a device's
+ location using the
+ <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">{@code requestLocationUpdates()}</a>
+ method in the fused location provider.
+
+<h2 id="connect">Connect to Location Services</h2>
+
+<p>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
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>,
+ follow the instructions in
+ <a href="retrieve-current.html">Getting the Last Known Location</a>, including
+ requesting the current location.</p>
+
+<p>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
+ <a href="retrieve-current.html">Getting the Last Known Location</a> shows you
+ how to get the last known location by calling
+ <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>.
+ 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}.</p>
+
+<p>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:</p>
+
<pre>
-<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-</pre>
-<!-- Check for Google Play services -->
-<h2 id="PlayServices">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 API reference documentation. 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()}
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.gms.location.sample.locationupdates" >
-</p>
-<p class="note">
- <strong>Note:</strong> 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}.
-</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
- } 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>
</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>
- Before you request location updates, you must first implement the interfaces that Location
- Services uses to communicate connection status to your app:
-</p>
+
+<h2 id="location-request">Set Up a Location Request</h2>
+
+<p>To store parameters for requests to the fused location provider, create a
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a>.
+ The parameters determine the levels of accuracy requested. For details of all
+ the options available in the location request, see the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a>
+ class reference. This lesson sets the update interval, fastest update
+ interval, and priority, as described below:</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>
+ <dt>
+ Update interval
+ </dt>
+ <dd>
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">{@code setInterval()}</a>
+ - 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).
+ </dd>
+ <dt>
+ Fastest update interval
+ </dt>
+ <dd>
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">{@code setFastestInterval()}</a>
+ - This method sets the <strong>fastest</strong> 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
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">{@code setInterval()}</a>.
+ If this rate is faster
+ than your app can handle, you may encounter problems with UI flicker or data
+ overflow. To prevent this, call
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">{@code setFastestInterval()}</a>
+ to set an upper limit to the update rate.
+ </dd>
+ <dt>Priority</dt>
+ <dd>
+ <p>
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setPriority(int)">{@code setPriority()}</a>
+ - 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:</p>
+ <ul>
+ <li>
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_BALANCED_POWER_ACCURACY">{@code PRIORITY_BALANCED_POWER_ACCURACY}</a>
+ - Use this setting to request location precision to within a city
+ block, which is an accuracy of approximately 100 meters. This is
+ considered a coarse level of accuracy, and is likely to consume less
+ power. With this setting, the location services are likely to use WiFi
+ and cell tower positioning. Note, however, that the choice of location
+ provider depends on many other factors, such as which sources are
+ available.</li>
+ <li>
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">{@code PRIORITY_HIGH_ACCURACY}</a>
+ - Use this setting to request the most precise location possible. With
+ this setting, the location services are more likely to use GPS
+ (Global Positioning System) to determine the location.</li>
+ <li><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_LOW_POWER">{@code PRIORITY_LOW_POWER}</a>
+ - Use this setting to request city-level precision, which is
+ an accuracy of approximately 10 kilometers. This is considered a
+ coarse level of accuracy, and is likely to consume less power.</li>
+ <li><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_NO_POWER">{@code PRIORITY_NO_POWER}</a>
+ - Use this setting if you need negligible impact on power consumption,
+ but want to receive location updates when available. With this
+ setting, your app does not trigger any location updates, but
+ receives locations triggered by other apps.</li>
+ </ul>
+ </dd>
</dl>
-<p>
- The following snippet shows how to specify the interfaces and define the methods:
-</p>
+
+<p>Create the location request and set the parameters as shown in this
+ code sample:</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());
- }
- }
- ...
+protected void createLocationRequest() {
+ LocationRequest mLocationRequest = new LocationRequest();
+ mLocationRequest.setInterval(10000);
+ mLocationRequest.setFastestInterval(5000);
+ mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
</pre>
-<h3>Define the location update callback</h3>
-<p>
- 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
- <a href="activity-recognition.html">Recognizing the User's Current Activity</a>, which
- presents a similar pattern.
-</p>
-<p>
- The callback method that Location Services invokes to send a location update to your app is
- specified in the
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">LocationListener</a></code>
- interface, in the method
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html#onLocationChanged(android.location.Location)">onLocationChanged()</a></code>.
- 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:
-</p>
+
+<p>The priority of
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">{@code PRIORITY_HIGH_ACCURACY}</a>,
+ 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.</p>
+
+<p class="note"><strong>Performance hint:</strong> 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.</p>
+
+<h2 id="updates">Request Location Updates</h2>
+
+<p>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
+ <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">{@code requestLocationUpdates()}</a>.
+ Do this in the
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
+ callback provided by Google API Client, which is called when the client is
+ ready.</p>
+
+<p>Depending on the form of the request, the fused location provider either
+ invokes the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener.onLocationChanged()}</a>
+ callback method and passes it a {@link android.location.Location} object, or
+ issues a
+ <a href="{@docRoot}reference/android/app/PendingIntent.html">{@code PendingIntent}</a>
+ 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.</p>
+
+<p>This lesson shows you how to get the update using the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a>
+ callback approach. Call
+ <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">{@code requestLocationUpdates()}</a>,
+ passing it your instance of the
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>,
+ the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a>
+ object,
+ and a <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a>.
+ Define a {@code startLocationUpdates()} method, called from the
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
+ callback, as shown in the following code sample:</p>
+
<pre>
-public class MainActivity extends FragmentActivity implements
- GooglePlayServicesClient.ConnectionCallbacks,
- GooglePlayServicesClient.OnConnectionFailedListener,
- LocationListener {
+@Override
+public void onConnected(Bundle connectionHint) {
...
- // Define the callback method that receives location updates
+ if (mRequestingLocationUpdates) {
+ startLocationUpdates();
+ }
+}
+
+protected void startLocationUpdates() {
+ LocationServices.FusedLocationApi.requestLocationUpdates(
+ mGoogleApiClient, mLocationRequest, this);
+}
+</pre>
+
+<p>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
+ <a href="#save-state">Save the State of the Activity</a>.
+
+<h2 id="callback">Define the Location Update Callback</h2>
+
+<p>The fused location provider invokes the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html#onLocationChanged(android.location.Location)">{@code LocationListener.onLocationChanged()}</a>
+ 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
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a>
+ 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:</p>
+
+<pre>
+public class MainActivity extends ActionBarActivity implements
+ ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
+ ...
@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();
}
- ...
-}
-</pre>
-<p>
- 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.
-</p>
-<!-- Specify update parameters -->
-<h2 id="UpdateParameters">Specify Update Parameters</h2>
-<p>
- Location Services allows you to control the interval between updates and the location accuracy
- you want, by setting the values in a
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a></code>
- object and then sending this object as part of your request to start updates.
-</p>
-<p>
- First, set the following interval parameters:
-</p>
-<dl>
- <dt>
- Update interval
- </dt>
- <dd>
- Set by
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>.
- 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.
- </dd>
- <dt>
- Fastest update interval
- </dt>
- <dd>
- Set by
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code>.
- This method sets the <b>fastest</b> 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
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>.
- 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><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code>
- to set an upper limit to the update rate.
- <p>
- Calling
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code>
- also helps to save power. When you request a preferred update rate by calling
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>,
- and a maximum rate by calling
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code>,
- 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
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>.
- </p>
- </dd>
-</dl>
-<p>
- Next, set the accuracy parameter. In a foreground app, you need constant location updates with
- high accuracy, so use the setting
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">LocationRequest.PRIORITY_HIGH_ACCURACY</a></code>.
-</p>
-<p>
- The following snippet shows how to set the update interval and accuracy in
- {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}:
-</p>
-<pre>
-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);
- ...
- }
- ...
-}
-</pre>
-<p class="note">
- <strong>Note:</strong> 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.
-</p>
-<!-- Start Location Updates -->
-<h2 id="StartUpdates">Start Location Updates</h2>
-<p>
- 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
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">requestLocationUpdates()</a></code>.
- 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
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code>
-</p>
-<p>
- 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()}.
-</p>
-<p>
- 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()}:
-</p>
-<pre>
-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);
- }
- }
- ...
}
</pre>
-<p>
- For more information about saving preferences, read
-<a href="{@docRoot}training/basics/data-storage/shared-preferences.html">Saving Key-Value Sets</a>.
-</p>
-<!--
- Stop Location Updates
- -->
-<h2 id="StopUpdates">Stop Location Updates</h2>
-<p>
- 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
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeLocationUpdates(com.google.android.gms.location.LocationListener)">removeLocationUpdates(LocationListener)</a></code>.
- For example:
-</p>
+
+<h2 id="stop-updates">Stop Location Updates</h2>
+
+<p>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.</p>
+
+<p>To stop location updates, call
+ <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#removeLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationListener)">{@code removeLocationUpdates()}</a>,
+ passing it your instance of the
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>
+ object and a
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a>,
+ as shown in the following code sample:</p>
+
<pre>
-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);
}
</pre>
-<p>
- 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.
-</p>
-<p>
- The next lesson, <a href="display-address.html">Displaying a Location Address</a>, shows you how
- to use the current location to display the current street address.
-</p>
+
+<p>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:</p>
+
+<pre>
+@Override
+public void onResume() {
+ super.onResume();
+ if (mGoogleApiClient.isConnected() && !mRequestingLocationUpdates) {
+ startLocationUpdates();
+ }
+}
+</pre>
+
+<h2 id="save-state">Save the State of the Activity</h2>
+
+<p>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.</p>
+
+<p>The following code sample shows how to use the activity's
+ <a href="{@docRoot}reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)">{@code onSaveInstanceState()}</a>
+ callback to save the instance state:</p>
+
+<pre>
+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);
+}
+</pre>
+
+<p>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:</p>
+
+<pre>
+@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();
+ }
+}
+</pre>
+
+<p>For more about saving instance state, see the
+ <a href="{@docRoot}reference/android/app/Activity.html#ConfigurationChanges">Android
+ Activity</a> class reference.</p>
+
+<p class="note"><strong>Note:</strong> 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
+ <a href="{@docRoot}training/basics/data-storage/shared-preferences.html">Saving
+ Key-Value Sets</a>.</p>
+
+<p>The next lesson,
+ <a href="display-address.html">Displaying a Location Address</a>, shows
+ you how to display the street address for a given location.</p>