This lesson teaches you to
You should also read
Try it out
LocationUpdates.zip
The lessons Retrieving the Current Location and
Receiving Location Updates describe how to get the
user's current location in the form of a 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.
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.
Note: Address lookup requires a backend service that is not included in the
core Android framework. If this backend service is not available,
Geocoder.getFromLocation()
returns an empty
list. The helper method isPresent()
, available
in API level 9 and later, checks to see if the backend service is available.
The snippets in the following sections assume that your app has already retrieved the
current location and stored it as a Location
object in the global
variable mLocation
.
Define the Address Lookup Task
To get an address for a given latitude and longitude, call
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 doInBackground()
method of an AsyncTask
.
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 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".
The following snippet shows how to add an indeterminate ProgressBar
to
your layout file:
<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" />
To create the background task, define a subclass of AsyncTask
that calls
getFromLocation()
and returns an address.
Define a TextView
object mAddress
to contain the returned
address, and a ProgressBar
object that allows you to control the
indeterminate activity indicator. For example:
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 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";
}
}
...
}
...
}
The next section shows you how to display the address in the user interface.
Define a Method to Display the Results
doInBackground()
returns the result of the address
lookup as a String
. This value is passed to
onPostExecute()
, where you do further processing
on the results. Since 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:
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); } ... }
The final step is to run the address lookup.
Run the Lookup Task
To get the address, call execute()
. For example, the
following snippet starts the address lookup when the user clicks the "Get Address" button:
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); } ... } ... }
The next lesson, Creating and Monitoring Geofences, demonstrates how to define locations of interest called geofences and how to use geofence monitoring to detect the user's proximity to a location of interest.