2010年11月17日 星期三

[Android]-使用MapView與事件處理

要在Android開發上使用MapView首先要先申請一組apiKey
步驟如下:
1.開啟本機Dos模式,輸入以下指令
keytool -list -alias androiddebugkey -keystore "Android SDK的debug.keystore路徑" -storepass android  -keypass android
筆者本機的debug.keystore路徑為"C:\Users\User\.android\debug.keystore"
執行後可以得到一組認証指紋如下:

2.接著拿這組認証指紋去Google網站上申請apikey
申請網址:http://code.google.com/intl/zh-TW/android/maps-api-signup.html

3.在layout的xml檔中加入下列宣告
<LinearLayout android:id="@+id/LinearLayout05"
              android:layout_width="fill_parent" 
              android:layout_height="wrap_content">
    <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="0Ci0OUAEfhUnW3nH7qRHKWtFUzqQDqBhRfZ92Aw"/>
  </LinearLayout>
4.最後在AndroidManifest.xml設定檔中要加入使用權限及library的宣告:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.chung.product"
          android:versionCode="1"
          android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".SafeAlert"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".GPSLocation"/>
        <uses-library android:name="com.google.android.maps"/>
    </application>
    <uses-sdk android:minSdkVersion="8" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
</manifest>

接下來介紹兩個常用的事件
1.第一個是座標改變時所觸發的事件
要完成這個功能會用到LocationManager及LocationHandler這兩個類別
範例碼如下:
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.location);

    MapView mapView = (MapView) findViewById(R.id.mapview);
        
    LocationManager mLocationManager = (LocationManager)          
                            getSystemService(Context.LOCATION_SERVICE);
    LocationHandler locationHandler = new LocationHandler();

    // 設定MapView可以縮放
    mapView.setBuiltInZoomControls(true);

    // 設定Zoom大小和地圖的中心點
    MapController mc = mapView.getController();
    mc.setZoom(INITIAL_ZOOM_LEVEL);
    mc.setCenter(new GeoPoint(INITIAL_LATITUDE, INITIAL_LONGITUDE));

    // 位置有變化時,登錄呼叫的方法
    mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
    0, 0, locationHandler);
}

public class LocationHandler implements LocationListener {
    // 位置有變化時,呼叫此method
    public void onLocationChanged(Location location) {
        GeoPoint gp = new GeoPoint((int) (location.getLatitude() * 1E6),
                                       (int) (location.getLongitude() * 1E6));
        Log.i(TAG,"Location Changed: " + gp.toString());
   
        mc.animateTo(gp);
    }

    public void onProviderDisabled(String provider) {
        // TODO
    }

    public void onProviderEnabled(String provider) {
        // TODO 
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO
    }
}
2.第二個是滑動MAP時所觸發的事件
下面的範例利用ItemizedOverlay在地圖貼上地標,並在滑動map時
持續把地標更新在地圖中央。
首先自訂一個類並繼承ItemizedOverlay
這裡最重要的觀念是,mapview上所觸發的事件,會先pass到overlay,
所以對於map上的事件行為要在overlay中實作。
public class MapItemizedOverlay extends ItemizedOverlay {
    private ArrayList mOverlays = new ArrayList();

    public MapItemizedOverlay(Drawable defaultMarker) {
        super(boundCenterBottom(defaultMarker));
    }

    public void addOverlay(OverlayItem overlay) {
        mOverlays.add(overlay);
        populate();
    }

    @Override
    protected OverlayItem createItem(int i) {
        return mOverlays.get(i);
    }

    @Override
    public int size() {
        return mOverlays.size();
    }

    // 在mapview上偵測到的touch event會先pass到overlay來
    @Override
    public boolean onTouchEvent(MotionEvent event, MapView v) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            // 清除舊的marker並貼上新的
            mapView.getOverlays().remove(0);
            OverlayItem overlayitem = new OverlayItem(
                           mapView.getMapCenter(), "", "");
            Drawable drawable = this.getResources().getDrawable(R.drawable.icon);
            itemizedOverlay = new MapItemizedOverlay(drawable);
            itemizedOverlay.addOverlay(overlayitem);
            mapView.getOverlays().add(itemizedOverlay);
        }
        return super.onTouchEvent(event, v);
    }
}
下面是執行結果畫面,隨著map的拖動,地標會隨時保持在地圖中央: