注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。
原文链接: http://developer.android.com/training/location/display-address.html
前两节课程讲解了如何以 Location 对象的形式(包含经纬度的信息)来获取用户的当前地理位置信息。虽然经纬度信息对于计算距离或者显示一个地图位置很有用,但在很多情况下,当前地点的地址往往作用更大。
Android API提供了一个特性,它可以针对经纬度信息估计出用户所在的街道地址。这节课将讲解如何使用这一地址查询功能。
Note:
地址查询需要一个没有包括在核心Android框架中的后端服务。如果这个后端服务无法获取, Geocoder.getFromLocation() 会返回一个空的list。辅助方法 isPresent() 在API 9及以上版本中可以获得,它可以用来检查后端服务是否可以获取。
下列章节中的样例代码均假设你的应用已经获取了当前地点,并将它以一个 Location 对象的形式存储于全局变量 mLocation 中。
一). 定义地址查询任务
要获取给定经纬度的地址信息,调用
Geocoder.getFromLocation()
,它会返回一个包含地址的list。该方法是同步的,并且会耗费较长的时间去执行,所以你应该在一个
AsyncTask
中的
doInBackground()
里面进行调用。
当你的应用在获取地址时,显示一个执行任务的标识告诉用户你的应用正在执行后台程序是有必要的。我们首先将这个标识的初始状态设置为 android:visibility="gone" ,这可以使得它初始时不可见并且从布局层次结构中移除。当你开始地址查询时,你应该将它的可见性设置为“ visible ”。
下面的代码片段展示了如何在你的布局文件中添加一个 ProgressBar :
< 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" />
要创建一个后台任务,定义一个 AsyncTask 的子类,用来调用 getFromLocation() 并返回地址。定义一个 名字叫 mAddress 的 TextView 对象,用来显示返回的地址,另外一个 ProgressBar 对象允许你可以对后台执行的标识进行控制,例如:
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" ; } } ... } ... }
在下一章节将会向你展示如何在用户接口显示地址。
二). 定义一个显示结果的方法
doInBackground() 返回的地址查询结果是一个String的类型。值被传递到 onPostExecute() 中,在这个方法里你将会对结果做进一步的处理。由于 onPostExecute() 方法是在UI线程中执行的,它可以用来更新用户接口;例如,它可以关闭进度条并且将结果显示给用户:
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); } ... }
最后的步骤就是要运行地址查询了。
三). 执行查询任务
要获取地址,调用 execute() 方法。例如,下面的代码片段在用户点击了“获取地址”这一按钮后,启动地址查询:
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); } ... } ... }
在下一节课,我们将会讲解如何去定义感兴趣的地点并调用地理围栏,以及如何使用它来检测用户是否接近感兴趣的地点。