• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Retrieving the Current Location
2trainingnavtop=true
3@jd:body
4<div id="tb-wrapper">
5<div id="tb">
6
7<h2>This lesson teaches you to</h2>
8<ol>
9    <li><a href="#AppPermissions">Specify App Permissions</a></li>
10    <li><a href="#CheckServices">Check for Google Play services</a></li>
11    <li><a href="#DefineCallbacks">Define Location Services Callbacks</a></li>
12    <li><a href="#ConnectClient">Connect the Location Client</a></li>
13    <li><a href="#GetLocation">Get the Current Location</a></li>
14</ol>
15
16<h2>You should also read</h2>
17<ul>
18    <li>
19        <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>
20    </li>
21</ul>
22
23<h2>Try it out</h2>
24
25<div class="download-box">
26  <a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download the sample</a>
27  <p class="filename">LocationUpdates.zip</p>
28</div>
29
30</div>
31</div>
32
33<p>
34    Location Services automatically maintains the user's current location, so all your app has to do
35    is retrieve it as needed. The location's accuracy is based on the location permissions you've
36    requested and location sensors that are currently active for the device.
37<p>
38    Location Services sends the current location to your app through a location client, which is
39    an instance of the Location Services class
40<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html">LocationClient</a></code>.
41    All requests for location information go through this client.
42</p>
43<p class="note">
44    <strong>Note:</strong> Before you start the lesson, be sure that your development environment
45    and test device are set up correctly. To learn more about this, read the
46    <a href="{@docRoot}google/play-services/setup.html">Setup</a> section in the Google Play
47    services guide.
48</p>
49<!--
50    Specify App Permissions
51 -->
52<h2 id="AppPermissions">Specify App Permissions</h2>
53<p>
54    Apps that use Location Services must request location permissions. Android has two location
55    permissions: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}
56    and {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. The
57    permission you choose controls the accuracy of the current location. If you request only coarse
58    location permission, Location Services obfuscates the returned location to an accuracy
59    that's roughly equivalent to a city block.
60</p>
61<p>
62    Requesting {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} implies
63    a request for {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}.
64</p>
65<p>
66    For example, to add {@link android.Manifest.permission#ACCESS_COARSE_LOCATION
67    ACCESS_COARSE_LOCATION}, insert the following as a child element of the
68    <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
69    element:
70</p>
71<pre>
72&lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/&gt;
73</pre>
74<!--
75    Check for Google Play Services
76 -->
77<h2 id="CheckServices">Check for Google Play Services</h2>
78<p>
79    Location Services is part of the Google Play services APK. Since it's hard to anticipate the
80    state of the user's device, you should always check that the APK is installed before you attempt
81    to connect to Location Services. To check that the APK is installed, call
82<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>,
83    which returns one of the
84    integer result codes listed in the reference documentation for
85<code><a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a></code>.
86    If you encounter an error, call
87<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code>
88    to retrieve localized dialog that prompts users to take the correct action, then display
89    the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the
90    user to correct the problem, in which case Google Play services may send a result back to your
91    activity. To handle this result, override the method
92    {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()}.
93</p>
94<p>
95    Since you usually need to check for Google Play services in more than one place in your code,
96    define a method that encapsulates the check, then call the method before each connection
97    attempt. The following snippet contains all of the code required to check for Google
98    Play services:
99</p>
100<pre>
101public class MainActivity extends FragmentActivity {
102    ...
103    // Global constants
104    /*
105     * Define a request code to send to Google Play services
106     * This code is returned in Activity.onActivityResult
107     */
108    private final static int
109            CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
110    ...
111    // Define a DialogFragment that displays the error dialog
112    public static class ErrorDialogFragment extends DialogFragment {
113        // Global field to contain the error dialog
114        private Dialog mDialog;
115        // Default constructor. Sets the dialog field to null
116        public ErrorDialogFragment() {
117            super();
118            mDialog = null;
119        }
120        // Set the dialog to display
121        public void setDialog(Dialog dialog) {
122            mDialog = dialog;
123        }
124        // Return a Dialog to the DialogFragment.
125        &#64;Override
126        public Dialog onCreateDialog(Bundle savedInstanceState) {
127            return mDialog;
128        }
129    }
130    ...
131    /*
132     * Handle results returned to the FragmentActivity
133     * by Google Play services
134     */
135    &#64;Override
136    protected void onActivityResult(
137            int requestCode, int resultCode, Intent data) {
138        // Decide what to do based on the original request code
139        switch (requestCode) {
140            ...
141            case CONNECTION_FAILURE_RESOLUTION_REQUEST :
142            /*
143             * If the result code is Activity.RESULT_OK, try
144             * to connect again
145             */
146                switch (resultCode) {
147                    case Activity.RESULT_OK :
148                    /*
149                     * Try the request again
150                     */
151                    ...
152                    break;
153                }
154            ...
155        }
156     }
157    ...
158    private boolean servicesConnected() {
159        // Check that Google Play services is available
160        int resultCode =
161                GooglePlayServicesUtil.
162                        isGooglePlayServicesAvailable(this);
163        // If Google Play services is available
164        if (ConnectionResult.SUCCESS == resultCode) {
165            // In debug mode, log the status
166            Log.d("Location Updates",
167                    "Google Play services is available.");
168            // Continue
169            return true;
170        // Google Play services was not available for some reason.
171        // resultCode holds the error code.
172        } else {
173            // Get the error dialog from Google Play services
174            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
175                    resultCode,
176                    this,
177                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
178
179            // If Google Play services can provide an error dialog
180            if (errorDialog != null) {
181                // Create a new DialogFragment for the error dialog
182                ErrorDialogFragment errorFragment =
183                        new ErrorDialogFragment();
184                // Set the dialog in the DialogFragment
185                errorFragment.setDialog(errorDialog);
186                // Show the error dialog in the DialogFragment
187                errorFragment.show(getSupportFragmentManager(),
188                        "Location Updates");
189            }
190        }
191    }
192    ...
193}
194</pre>
195<p>
196    Snippets in the following sections call this method to verify that Google Play services is
197    available.
198</p>
199<!--
200    Define Location Services Callbacks
201 -->
202<h2 id="DefineCallbacks">Define Location Services Callbacks</h2>
203<p>
204    To get the current location, create a location client, connect it
205    to Location Services, and then call its
206<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>
207    method. The return value  is the best, most recent location, based on the permissions your
208    app requested and the currently-enabled location sensors.
209<p>
210<p>
211    Before you create the location client, implement the interfaces that Location Services uses to
212    communicate with your app:
213</p>
214<dl>
215    <dt>
216<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code>
217    </dt>
218    <dd>
219        Specifies methods that Location Services calls when a location client is connected or
220        disconnected.
221    </dd>
222    <dt>
223<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code>
224    </dt>
225    <dd>
226        Specifies a method that Location Services calls if an error occurs while attempting to
227        connect the location client. This method uses the previously-defined {@code showErrorDialog}
228        method to display an error dialog that attempts to fix the problem using Google Play
229        services.
230    </dd>
231</dl>
232<p>
233    The following snippet shows how to specify the interfaces and define the methods:
234</p>
235<pre>
236public class MainActivity extends FragmentActivity implements
237        GooglePlayServicesClient.ConnectionCallbacks,
238        GooglePlayServicesClient.OnConnectionFailedListener {
239    ...
240    /*
241     * Called by Location Services when the request to connect the
242     * client finishes successfully. At this point, you can
243     * request the current location or start periodic updates
244     */
245    &#64;Override
246    public void onConnected(Bundle dataBundle) {
247        // Display the connection status
248        Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
249
250    }
251    ...
252    /*
253     * Called by Location Services if the connection to the
254     * location client drops because of an error.
255     */
256    &#64;Override
257    public void onDisconnected() {
258        // Display the connection status
259        Toast.makeText(this, "Disconnected. Please re-connect.",
260                Toast.LENGTH_SHORT).show();
261    }
262    ...
263    /*
264     * Called by Location Services if the attempt to
265     * Location Services fails.
266     */
267    &#64;Override
268    public void onConnectionFailed(ConnectionResult connectionResult) {
269        /*
270         * Google Play services can resolve some errors it detects.
271         * If the error has a resolution, try sending an Intent to
272         * start a Google Play services activity that can resolve
273         * error.
274         */
275        if (connectionResult.hasResolution()) {
276            try {
277                // Start an Activity that tries to resolve the error
278                connectionResult.startResolutionForResult(
279                        this,
280                        CONNECTION_FAILURE_RESOLUTION_REQUEST);
281                /*
282                 * Thrown if Google Play services canceled the original
283                 * PendingIntent
284                 */
285            } catch (IntentSender.SendIntentException e) {
286                // Log the error
287                e.printStackTrace();
288            }
289        } else {
290            /*
291             * If no resolution is available, display a dialog to the
292             * user with the error.
293             */
294            showErrorDialog(connectionResult.getErrorCode());
295        }
296    }
297    ...
298}
299</pre>
300<!--
301    Connect the Location Client
302 -->
303<h2 id="ConnectClient">Connect the Location Client</h2>
304<p>
305    Now that the callback methods are in place, create the location client and connect it to
306    Location Services.
307</p>
308<p>
309    You should create the location client in {@link android.support.v4.app.FragmentActivity#onCreate
310    onCreate()}, then connect it in
311    {@link android.support.v4.app.FragmentActivity#onStart onStart()}, so that Location Services
312    maintains the current location while your activity is fully visible. Disconnect the client in
313    {@link android.support.v4.app.FragmentActivity#onStop onStop()}, so that when your app is not
314    visible, Location Services is not maintaining the current location. Following this pattern of
315    connection and disconnection helps save battery power. For example:
316</p>
317<p class="note">
318    <strong>Note:</strong> The current location is only maintained while a location client is
319    connected to Location Service. Assuming that no other apps are connected to Location Services,
320    if you disconnect the client and then sometime later call
321<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>,
322    the result may be out of date.
323</p>
324<pre>
325public class MainActivity extends FragmentActivity implements
326        GooglePlayServicesClient.ConnectionCallbacks,
327        GooglePlayServicesClient.OnConnectionFailedListener {
328    ...
329    &#64;Override
330    protected void onCreate(Bundle savedInstanceState) {
331        ...
332        /*
333         * Create a new location client, using the enclosing class to
334         * handle callbacks.
335         */
336        mLocationClient = new LocationClient(this, this, this);
337        ...
338    }
339    ...
340    /*
341     * Called when the Activity becomes visible.
342     */
343    &#64;Override
344    protected void onStart() {
345        super.onStart();
346        // Connect the client.
347        mLocationClient.connect();
348    }
349    ...
350    /*
351     * Called when the Activity is no longer visible.
352     */
353    &#64;Override
354    protected void onStop() {
355        // Disconnecting the client invalidates it.
356        mLocationClient.disconnect();
357        super.onStop();
358    }
359    ...
360}
361</pre>
362<!--
363    Get the Current Location
364 -->
365<h2 id="GetLocation">Get the Current Location</h2>
366<p>
367    To get the current location, call
368<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>.
369    For example:
370</p>
371<pre>
372public class MainActivity extends FragmentActivity implements
373        GooglePlayServicesClient.ConnectionCallbacks,
374        GooglePlayServicesClient.OnConnectionFailedListener {
375    ...
376    // Global variable to hold the current location
377    Location mCurrentLocation;
378    ...
379    mCurrentLocation = mLocationClient.getLastLocation();
380    ...
381}
382</pre>
383<p>
384    The next lesson, <a href="receive-location-updates.html">Receiving Location Updates</a>, shows
385    you how to receive periodic location updates from Location Services.
386</p>
387