Uses GoogleApiClient to connect to Play services. Uses the latest Fused Location Provider API. Updates the entire tutorial and code sample for clarity and correctness. Bug: 17109822 Change-Id: I42cc36f861d0455ef9c07b793c64038c572a6e8a
418 lines
20 KiB
Plaintext
418 lines
20 KiB
Plaintext
page.title=Receiving Location Updates
|
|
trainingnavtop=true
|
|
@jd:body
|
|
|
|
<div id="tb-wrapper">
|
|
<div id="tb">
|
|
|
|
<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>
|
|
<li>
|
|
<a href="{@docRoot}google/play-services/setup.html">Setting up Google Play
|
|
Services</a>
|
|
</li>
|
|
<li>
|
|
<a href="retrieve-current.html">Getting the Last Known Location</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<h2>Try it out</h2>
|
|
|
|
<ul>
|
|
<li>
|
|
<a href="https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates" class="external-link">LocationUpdates</a>
|
|
</li>
|
|
</ul>
|
|
</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>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>
|
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
package="com.google.android.gms.location.sample.locationupdates" >
|
|
|
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
|
</manifest>
|
|
</pre>
|
|
|
|
<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>
|
|
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>Create the location request and set the parameters as shown in this
|
|
code sample:</p>
|
|
|
|
<pre>
|
|
protected void createLocationRequest() {
|
|
LocationRequest mLocationRequest = new LocationRequest();
|
|
mLocationRequest.setInterval(10000);
|
|
mLocationRequest.setFastestInterval(5000);
|
|
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
|
|
}
|
|
</pre>
|
|
|
|
<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>
|
|
@Override
|
|
public void onConnected(Bundle connectionHint) {
|
|
...
|
|
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) {
|
|
mCurrentLocation = location;
|
|
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
|
|
updateUI();
|
|
}
|
|
|
|
private void updateUI() {
|
|
mLatitudeTextView.setText(String.valueOf(mCurrentLocation.getLatitude()));
|
|
mLongitudeTextView.setText(String.valueOf(mCurrentLocation.getLongitude()));
|
|
mLastUpdateTimeTextView.setText(mLastUpdateTime);
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<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>
|
|
@Override
|
|
protected void onPause() {
|
|
super.onPause();
|
|
stopLocationUpdates();
|
|
}
|
|
|
|
protected void stopLocationUpdates() {
|
|
LocationServices.FusedLocationApi.removeLocationUpdates(
|
|
mGoogleApiClient, this);
|
|
}
|
|
</pre>
|
|
|
|
<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>
|