在 Android 裡使用 MapView,與一般的 Android 應用程式有些不一樣的地方。
Google Maps Library
首先就是 Android 平台沒有內建 Google Maps Library,所以有兩個地方要注意。
第一,在建立 Android 專案時,Build Target 得用 Google APIs,而非以前用的 Android 2.2。
第二,必須在 AndroidManifest.xml 裡宣告使用 Google Maps Library,否則會出現 ClassNotFoundException。
<application android:icon="@drawable/icon" android:label="@string/app_name"> <activity ...>...</activity> <uses-library android:name="com.google.android.maps"/> </application>這樣就可以在 XML 裡使用 MapView 了。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.google.android.maps.MapView android:id="@+id/gmap" android:apiKey="..." android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true"/> </LinearLayout>因為 MapView 不是 Android 內建的 class,所以在 XML 設定裡得用全名,就是 com.google.android.maps.MapView,為什麼不直接內建 MapView 到 Android 呢?簡單說就是,Android 是 Open source,而 Google Maps 是 Google 的(Android 的 Google 專案:Google API),親兄弟還是要明算帳。
再來就是要用 MapActivity 取代原本的 Activity,否則會出現「MapViews can only be created inside instances of MapActivity.」的 exception,MapActivity 處理了連網取資料、資料暫存、activity life cycle 等等重要的動作。
public class Gmap extends MapActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected boolean isRouteDisplayed() { return false; } }完成後,在 Emulator 上執行,出現「No compatible targets were found. Do you wish to add a new Android Virtual Device?」的訊息,原因是 MapView 用的 target 是 Google APIs,而非原來的 Android 2.2,馬上來建一個 AVD。
重新啟動,emulator ok了,但是只看到一張 Google 方格紙,沒看到地圖,在 LogCat 裡看到錯誤訊息「Couldn't get connection factory client」,原來是忘了在 MapView 裡加上 Google Maps API Key。
取得 Android emulator 專用的 Google Maps API Key
取得 Android 使用的 Google Maps API Key 方法跟網頁用的 API Key 的方法不太一樣,網頁用的只要提供網址就可以,Android 用的得提供「Certificate's MD5 fingerprint」,先不管這是什麼,重點是要怎麼取得?請參考 Getting the MD5 Fingerprint of the SDK Debug Certificate,執行以下的命令:
keytool -list -alias androiddebugkey -keystore <User Home>\.android\debug.keystore -storepass android -keypass android要將 <User Home> 替換掉,這樣就可以取得「認證指紋 (MD5)」,然後到 Sign Up for the Android Maps API,輸入認證指紋就可以取得 API Key,最後將 API Key 填入 MapView 裡的 android:apiKey 就可以了往下一步前進了。
Android 應用程式的權限管理
重新啟動 emulator,還是只看到一張 Google 方格紙,原來是沒有開放 Android 應用程式的網路存取權限,開啟 AndroidManifest.xml 加入以下三個設定。
<manifest ...> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET"/> <application ...</application> </manifest>因為 MapActivity 會將檔案 cache 起來,所以需要開放檔案存取權限,就是前兩個設定,最後一個是開放網路存取權限。
地圖終於出現了!
我在哪裡?
Google API 裡有關 Google Maps 的主要 class 有三:
- MapView 提供所有跟地圖設定相關的 API 可以使用,如是否顯示放大縮小工具、切換為衛星地圖等等。
- MapController 控制地圖的縮放與移動。
- MyLocationOverlay 則是結合 GPS 提供目前所在的相關資訊。
public class Gmap extends MapActivity implements OnClickListener { private MapView mapView; private MapController mapCtrl; private MyLocationOverlay myLoc; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.mapView = (MapView) this.findViewById(R.id.gmap); this.mapCtrl = mapView.getController(); // 顯示縮放工具 this.mapView.setBuiltInZoomControls(true); // 設定 Button 功能 ((Button) this.findViewById(R.id.streetViewBtn)).setOnClickListener(this); ((Button) this.findViewById(R.id.satelliteViewBtn)).setOnClickListener(this); // 初始化 MyLocationOverlay this.myLoc = new MyLocationOverlay(this, this.mapView); // 註冊每當位置改變時執行的 runnable myLoc.runOnFirstFix(new Runnable() { @Override public void run() { // 移動地圖中心點到目前的位置 mapCtrl.animateTo(myLoc.getMyLocation()); } }); // 將目前位置標記 this.mapView.getOverlays().add(myLoc); } @Override protected void onPause() { super.onPause(); // Android 應用程式背景執行時,關閉位置偵測 this.myLoc.disableMyLocation(); this.myLoc.disableCompass(); } @Override protected void onResume() { super.onResume(); // Android 應用程式前景執行時,啟動位置偵測 this.myLoc.enableMyLocation(); this.myLoc.enableCompass(); } @Override public void onClick(View v) { // 使用主 activity 實做 OnClickListener 以改進效能 switch (v.getId()) { case R.id.streetViewBtn: this.mapView.setSatellite(false); break; case R.id.satelliteViewBtn: this.mapView.setSatellite(true); break; } } @Override protected boolean isRouteDisplayed() { return false; } }XML 設定檔,利用 layout_weight 將 Button 放在最下方,剩餘空間全做地圖顯示用。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.google.android.maps.MapView android:id="@+id/gmap" android:apiKey="0A...A" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:clickable="true"/> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="0"> <Button android:id="@+id/streetViewBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="街道"/> <Button android:id="@+id/satelliteViewBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="衛星"/> </LinearLayout> </LinearLayout>
事實上,在 emulator 上執行上面的程式是不會有作用的,因為 emulator 沒有 GPS 可以用。
貼心的 Google 在 Eclipse 提供了一個 Emulator Control View,透過這個 View,就可以任意輸入手機座標來驅動上面的範例。
請問我在開啟管理權限的地方會出現錯誤
回覆刪除是為什麼呢??
請問我在開啟管理權限那裡會出現錯誤
回覆刪除是為什麼呢?
請問是在開啟 AndroidManifest.xml 時出現錯誤的嗎?是檔案開不起來嗎?如果是這樣,請參考 http://cw1057.blogspot.com/2011/03/orgeclipsecoreruntimecoreexception.html 這篇文章。
回覆刪除如果不是這個問題,或者你可以提供詳細一點的資訊,如錯誤訊息。
謝謝你!這篇文章還蠻清楚的^^
回覆刪除Android 應用程式的權限管理
回覆刪除執行後 地圖沒有出現??
是為什麼??