地理編碼(Geocoding)與地理反編碼(Reverse Geocoding)是地圖操作中的常見操作,前者表示通過街道位址請求空間坐标,後者表示通過空間坐标請求街道位址。通俗的說,二者就是街道位址與經緯度的轉換。舉例來說,前者就是輸入查詢"上海市楊浦區四平路1239号"得到(31.285207060526762, 121.50546412914991),而後者則表示這個反過程。
在實際的移動開發過程中,地圖相關的操作對于地理編碼與地理反編碼的使用都是十分普遍。幸運的是,Android的MapView控件中對于這兩者都進行了封裝,是以可以友善的利用Google Map Service進行二者查詢。下面将對開發過程做一個簡單介紹。
首先必須進行MapKey的申請,任何地圖的顯示都需要申請一個MapKey。具體的申請步驟可見
http://code.google.com/intl/zh-CN/android/maps-api-signup.html
然後可以建立一個基于Google APIs的程式,并且在AndroidManifest.xml中加入地圖API的支援。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.learn2develop.GoogleMaps"
android:versionCode="1"
android:versionName="1.0.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<uses-library android:name="com.google.android.maps" />
<activity android:name=".MapsActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
</xml>
接着可以在主Layout檔案中加入對于地圖的顯示,這裡需要加入剛才申請的MapKey,否則地圖将無法正常顯示。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
android:id="@+id/mapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:enabled="true"
android:clickable="true"
android:apiKey="MapKey"
/>
</RelativeLayout>
接着在主Activity的JAVA檔案進行修改,支援地圖顯示。
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import android.os.Bundle;
public class MapsActivity extends MapActivity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MapView mapView = (MapView) findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
}
}
此時運作程式,地圖應該就可以正常顯示了,見下圖。
此時我們再向程式中加入地理編碼與地理反編碼的功能,其參考代碼如下。
地理編碼:
Geocoder geoCoder = new Geocoder(this, Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocationName(
"上海市楊浦區四平路1239号", 5);
String add = "";
if (addresses.size() > 0) {
p = new GeoPoint(
(int) (addresses.get(0).getLatitude() * 1E6),
(int) (addresses.get(0).getLongitude() * 1E6));
mc.animateTo(p);
mapView.invalidate();
}
} catch (IOException e) {
e.printStackTrace();
}
地理反編碼,其中MapOverlay為地圖圖層上的疊加圖層,用于辨別的顯示以及點選事件的捕捉。
class MapOverlay extends com.google.android.maps.Overlay
{
@Override
public boolean draw(Canvas canvas, MapView mapView,
boolean shadow, long when)
{
//...
}
@Override
public boolean onTouchEvent(MotionEvent event, MapView mapView)
{
//---when user lifts his finger---
if (event.getAction() == 1) {
GeoPoint p = mapView.getProjection().fromPixels(
(int) event.getX(),
(int) event.getY());
Geocoder geoCoder = new Geocoder(
getBaseContext(), Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocation(
p.getLatitudeE6() / 1E6,
p.getLongitudeE6() / 1E6, 1);
String add = "";
if (addresses.size() > 0)
{
for (int i=0; i<addresses.get(0).getMaxAddressLineIndex();
i++)
add += addresses.get(0).getAddressLine(i) + "/n";
}
Toast.makeText(getBaseContext(), add, Toast.LENGTH_SHORT).show();
}
catch (IOException e) {
e.printStackTrace();
}
return true;
}
else
return false;
}
}
最終實作結果如下圖所示,地理編碼,查詢“上海市楊浦區四平路1239号”,結果其實略有偏差。中國的位址與郵編比較混亂,是以結果有些地方無法做到完全準确。
地理反編碼
本文系“首屆 Google 暑期大學生部落格分享大賽——2010 Andriod 篇”參賽文章