page.title=Displaying a Location Address trainingnavtop=true @jd:body <div id="tb-wrapper"> <div id="tb"> <h2>This lesson teaches you to</h2> <ol> <li><a href="#DefineTask">Define the Address Lookup Task</a></li> <li><a href="#DisplayResults">Define a Method to Display the Results</a></li> <li><a href="#RunTask">Run the Lookup Task</a></li> </ol> <h2>You should also read</h2> <ul> <li> <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a> </li> <li> <a href="retrieve-current.html">Retrieving the Current Location</a> </li> <li> <a href="receive-location-updates.html">Receiving Location Updates</a> </li> </ul> <h2>Try it out</h2> <div class="download-box"> <a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download the sample app</a> <p class="filename">LocationUpdates.zip</p> </div> </div> </div> <p> The lessons <a href="retrieve-current.html">Retrieving the Current Location</a> and <a href="receive-location-updates.html">Receiving Location Updates</a> describe how to get the user's current location in the form of a {@link android.location.Location} object that contains latitude and longitude coordinates. Although latitude and longitude are useful for calculating distance or displaying a map position, in many cases the address of the location is more useful. </p> <p> The Android platform API provides a feature that returns an estimated street addresses for latitude and longitude values. This lesson shows you how to use this address lookup feature. </p> <p class="note"> <strong>Note:</strong> Address lookup requires a backend service that is not included in the core Android framework. If this backend service is not available, {@link android.location.Geocoder#getFromLocation Geocoder.getFromLocation()} returns an empty list. The helper method {@link android.location.Geocoder#isPresent isPresent()}, available in API level 9 and later, checks to see if the backend service is available. </p> <p> The snippets in the following sections assume that your app has already retrieved the current location and stored it as a {@link android.location.Location} object in the global variable {@code mLocation}. </p> <!-- Define the address lookup task --> <h2 id="DefineTask">Define the Address Lookup Task</h2> <p> To get an address for a given latitude and longitude, call {@link android.location.Geocoder#getFromLocation Geocoder.getFromLocation()}, which returns a list of addresses. The method is synchronous, and may take a long time to do its work, so you should call the method from the {@link android.os.AsyncTask#doInBackground doInBackground()} method of an {@link android.os.AsyncTask}. </p> <p> While your app is getting the address, display an indeterminate activity indicator to show that your app is working in the background. Set the indicator's initial state to {@code android:visibility="gone"}, to make it invisible and remove it from the layout hierarchy. When you start the address lookup, you set its visibility to "visible". </p> <p> The following snippet shows how to add an indeterminate {@link android.widget.ProgressBar} to your layout file: </p> <pre> <ProgressBar android:id="@+id/address_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:indeterminate="true" android:visibility="gone" /> </pre> <p> To create the background task, define a subclass of {@link android.os.AsyncTask} that calls {@link android.location.Geocoder#getFromLocation getFromLocation()} and returns an address. Define a {@link android.widget.TextView} object {@code mAddress} to contain the returned address, and a {@link android.widget.ProgressBar} object that allows you to control the indeterminate activity indicator. For example: </p> <pre> public class MainActivity extends FragmentActivity { ... private TextView mAddress; private ProgressBar mActivityIndicator; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... mAddress = (TextView) findViewById(R.id.address); mActivityIndicator = (ProgressBar) findViewById(R.id.address_progress); } ... /** * A subclass of AsyncTask that calls getFromLocation() in the * background. The class definition has these generic types: * Location - A {@link android.location.Location} object containing * the current location. * Void - indicates that progress units are not used * String - An address passed to onPostExecute() */ private class GetAddressTask extends AsyncTask<Location, Void, String> { Context mContext; public GetAddressTask(Context context) { super(); mContext = context; } ... /** * Get a Geocoder instance, get the latitude and longitude * look up the address, and return it * * @params params One or more Location objects * @return A string containing the address of the current * location, or an empty string if no address can be found, * or an error message */ @Override protected String doInBackground(Location... params) { Geocoder geocoder = new Geocoder(mContext, Locale.getDefault()); // Get the current location from the input parameter list Location loc = params[0]; // Create a list to contain the result address List<Address> addresses = null; try { /* * Return 1 address. */ addresses = geocoder.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1); } catch (IOException e1) { Log.e("LocationSampleActivity", "IO Exception in getFromLocation()"); e1.printStackTrace(); return ("IO Exception trying to get address"); } catch (IllegalArgumentException e2) { // Error message to post in the log String errorString = "Illegal arguments " + Double.toString(loc.getLatitude()) + " , " + Double.toString(loc.getLongitude()) + " passed to address service"; Log.e("LocationSampleActivity", errorString); e2.printStackTrace(); return errorString; } // If the reverse geocode returned an address if (addresses != null && addresses.size() > 0) { // Get the first address Address address = addresses.get(0); /* * Format the first line of address (if available), * city, and country name. */ String addressText = String.format( "%s, %s, %s", // If there's a street address, add it address.getMaxAddressLineIndex() > 0 ? address.getAddressLine(0) : "", // Locality is usually a city address.getLocality(), // The country of the address address.getCountryName()); // Return the text return addressText; } else { return "No address found"; } } ... } ... } </pre> <p> The next section shows you how to display the address in the user interface. </p> <!-- Define a method to display the address --> <h2 id="DisplayResults">Define a Method to Display the Results</h2> <p> {@link android.os.AsyncTask#doInBackground doInBackground()} returns the result of the address lookup as a {@link java.lang.String}. This value is passed to {@link android.os.AsyncTask#onPostExecute onPostExecute()}, where you do further processing on the results. Since {@link android.os.AsyncTask#onPostExecute onPostExecute()} runs on the UI thread, it can update the user interface; for example, it can turn off the activity indicator and display the results to the user: </p> <pre> private class GetAddressTask extends AsyncTask<Location, Void, String> { ... /** * A method that's called once doInBackground() completes. Turn * off the indeterminate activity indicator and set * the text of the UI element that shows the address. If the * lookup failed, display the error message. */ @Override protected void onPostExecute(String address) { // Set activity indicator visibility to "gone" mActivityIndicator.setVisibility(View.GONE); // Display the results of the lookup. mAddress.setText(address); } ... } </pre> <p> The final step is to run the address lookup. </p> <!-- Get and display the address --> <h2 id="RunTask">Run the Lookup Task</h2> <p> To get the address, call {@link android.os.AsyncTask#execute execute()}. For example, the following snippet starts the address lookup when the user clicks the "Get Address" button: </p> <pre> public class MainActivity extends FragmentActivity { ... /** * The "Get Address" button in the UI is defined with * android:onClick="getAddress". The method is invoked whenever the * user clicks the button. * * @param v The view object associated with this method, * in this case a Button. */ public void getAddress(View v) { // Ensure that a Geocoder services is available if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && Geocoder.isPresent()) { // Show the activity indicator mActivityIndicator.setVisibility(View.VISIBLE); /* * Reverse geocoding is long-running and synchronous. * Run it on a background thread. * Pass the current location to the background task. * When the task finishes, * onPostExecute() displays the address. */ (new GetAddressTask(this)).execute(mLocation); } ... } ... } </pre> <p> The next lesson, <a href="geofencing.html">Creating and Monitoring Geofences</a>, demonstrates how to define locations of interest called <b>geofences</b> and how to use geofence monitoring to detect the user's proximity to a location of interest. </p>