第 14 章 google 地圖與定位服務

94
第 14 第 Google 第第第第第第第 14-1 定定定定 - 定定定定 14-2 定定定定定定 - 定定定定定定 14-3 定定定定定定定定定 -GPS 定定定定定定 14-4 定定 Google Maps API-My 定定 14-5 定定 Google 定定 - 定定定定定定

Upload: myles-barrett

Post on 03-Jan-2016

42 views

Category:

Documents


0 download

DESCRIPTION

第 14 章 Google 地圖與定位服務. 14-1 定位服務 - 我在哪裡 14-2 地圖解碼服務 - 找出景點座標 14-3 本地服務與定位應用 -GPS 景點防撞雷達 14-4 使用 Google Maps API-My 地圖 14-5 標記 Google 地圖 - 追蹤個人行蹤. 14-1 定位服務-我在哪裡. 14-1-1 Android 的定位服務與座標 14-1-2 使用定位服務 - 我在哪裡. 14-1-1 Android 的定位服務與座標 - 說明. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 14 章  Google 地圖與定位服務

第 14 章 Google 地圖與定位服務

14-1 定位服務-我在哪裡 14-2 地圖解碼服務-找出景點座標 14-3 本地服務與定位應用-GPS景點防撞雷達 14-4 使用Google Maps API-My地圖 14-5 標記Google地圖-追蹤個人行蹤

Page 2: 第 14 章  Google 地圖與定位服務

14-1 定位服務 -我在哪裡

14-1-1 Android 的定位服務與座標 14-1-2 使用定位服務 - 我在哪裡

Page 3: 第 14 章  Google 地圖與定位服務

14-1-1 Android 的定位服務與座標 - 說明

Android 行動裝置結合定位功能和 Google 地圖建立的「位置感知服務」( Location-based Service, LBS ),這是一項十分實用的功能, LBS 應用程式可以追蹤你的位置和提供一些額外服務,例如:找出附近的咖啡廳、停車場、自動櫃員機或加油站等。

Android 作業系統提供 LocationManager 類別的定位服務來幫助我們存取行動裝置目前的定位資料,包含:緯度( Latitude )、經度( Longitude )和高度( Altitude )等。

Page 4: 第 14 章  Google 地圖與定位服務

14-1-1 Android 的定位服務與座標 - 種類

GPS 定位提供者:提供者名稱字串為 "gps" ,它是使用 GPS( Global Positioning System )的衛星訊號來定位,可以提供精確的位置資訊,但是無法收到衛星訊號的室內並無法使用。

網路定位提供者;提供者名稱字串為 "network" ,它是直接使用電信公司基地台來執行三角定位,其提供的位置資訊較不精確,但是可以在室內使用。

Page 5: 第 14 章  Google 地圖與定位服務

14-1-1 Android 的定位服務與座標 - 座標

定位服務最主要的目的是找出行動裝置目前位置的經緯度座標,經緯度是經度與緯度合稱的座標系統,也稱為地理座標系統,它是使用三度空間的球面來定義地球表面各點的座標系統,能夠標示地球表面上的任何一個位置。經度與緯度的說明,如下所示:• 緯度:地球表面某一點距離地球赤道以南或以北的度數,其值為

0至 90 度,赤道以北的緯度叫北緯(符號為 N );赤道以南的緯度稱南緯(符號為 S )。

• 經度:地球表面上某一點距離本初子午線(一條南北方向經過倫敦格林威治天文台舊址的子午線)以東或以西的度數,簡單的說,本初子午線的經度是 0 度,其他地點的經度是向東從 0到 180度,即東經(符號為 W )或向西從 0到 180 度,即西經(符號為E )。

Page 6: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡 ( 說明 )

我在哪裡是定位服務的最簡單應用,可以顯示目前行動裝置的經緯度座標。

Page 7: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟一:開啟和執行 Android 專案 請啟動 Eclipse IDE 開啟 Android

專案 Ch14_1_2 ,內含 1個 Java類別檔和版面配置檔 main.xml,執行可以看到程式顯示目前的位置座標,按【顯示 Google 地圖】鈕,可以啟動 Google 地圖顯示此座標附近的地圖,即台北火車站,如下圖所示:

Page 8: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟二:建立我在哪裡使用介面的版面配置 我在哪裡使用介面的版面配置是定義在 main.xml 檔,使用

LinearLayout 垂直編排 1個 TextView和 Button 元件,如下所示:<TextView android:id="@+id/output" android:layout_width="fill_parent" android:layout_height="wrap_content"/><Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 顯示 Google 地圖 " android:onClick="button1_Click"/>

Page 9: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -1

在 Ch14_1_2Activity 活動類別的開頭宣告成員的LocationManager和 Location 物件變數,如下所示:public class Ch14_1_2Activity extends Activity { private LocationManager manager; private Location currentLocation; private String best; …}

Page 10: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -2

onCreate() 方法 在覆寫的 onCreate() 方法載入版面配置後,可以取得系統服務的

LocationManager 物件, if 條件檢查是否有啟用 GPS ,如下所示:@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); manager = (LocationManager)getSystemService( LOCATION_SERVICE); if (!manager.isProviderEnabled( LocationManager.GPS_PROVIDER)) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(" 定位管理 ") .setMessage("GPS 目前狀態是尚未啟用 .\n"

Page 11: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -3

+" 請問你是否現在就設定啟用 GPS?") .setPositiveButton(" 啟用 ", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent i = new Intent(Settings. ACTION_LOCATION_SOURCE_SETTINGS); startActivity(i); } }) .setNegativeButton(" 不啟用 ", null).create().show(); }}

Page 12: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -4

onResume() 方法 在覆寫 onResume() 方法建立 Criteria 物件設定如何選擇提供者,以便

取得最佳或符合你需求的定位提供者,然後就可以呼叫getrBestProvider() 方法取得最佳提供者字串,參數是 Criteria 物件,如下所示:@Overrideprotected void onResume() { super.onResume(); Criteria criteria = new Criteria(); best = manager.getBestProvider(criteria, true); int minTime = 5000; // 毫秒 float minDistance = 5; // 公尺 if (best != null) { currentLocation = manager.getLastKnownLocation(best);

Page 13: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -5

manager.requestLocationUpdates(best, minTime, minDistance, listener); } else { currentLocation = manager.getLastKnownLocation( LocationManager.GPS_PROVIDER); manager.requestLocationUpdates( LocationManager.GPS_PROVIDER, minTime, minDistance, listener); } updatePosition();}

Page 14: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -6

onPause() 方法 在覆寫 onPause() 方法呼叫 removeUpdates() 方法

取消周期更新位置,如下所示:@Overrideprotected void onPause() { super.onPause(); manager.removeUpdates(listener); }

Page 15: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -7

updatePosition() 方法 在自訂 updatePosition() 方法更新 TextView 元件顯示的位

置資訊,如下所示:private void updatePosition() { TextView output; output = (TextView) findViewById(R.id.output); if (currentLocation == null) { output.setText(" 取得定位資訊中 ..."); } else { output.setText(getLocationInfo(currentLocation)); }}

Page 16: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -8

LocationListener傾聽者物件 使用匿名內層類別實作 LocationListener 介面來建立此物件,需要實作

4 個方法,如下所示:private LocationListener listener = new LocationListener() { @Override public void onLocationChanged(Location location) { currentLocation = location; updatePosition(); } @Override public void onProviderDisabled(String provider) { } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } };

Page 17: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -9

getLocationInfo() 方法 在自訂的 getLocationInfo() 方法可以從參數 Loaction 物件取得定位資

訊,如下所示:public String getLocationInfo(Location location) { StringBuffer str = new StringBuffer(); str.append(" 定位提供者 (Provider): "+ location.getProvider()); str.append("\n 緯度 (Latitude): " + Double.toString(location.getLatitude())); str.append("\n 經度 (Longitude): " + Double.toString(location.getLongitude())); str.append("\n 高度 (Altitude): " + Double.toString(location.getAltitude())); return str.toString();}

Page 18: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟三:建立 Activity 活動類別使用定位服務 -10

button1_Click()事件處理方法 button1_Click()事件處理方法可以依據目前的位置座標來

啟動 Google 地圖,它是使用 Intent 物件啟動 Google 地圖程式,首先取得經緯度座標 longitude和 latitude ,如下所示:public void button1_Click(View view) { float latitude = (float) currentLocation.getLatitude(); float longitude = (float) currentLocation.getLongitude(); String uri = String.format("geo:%f,%f?z=18", latitude, longitude); Intent geoMap = new Intent( Intent.ACTION_VIEW,Uri.parse(uri)); startActivity(geoMap);}

Page 19: 第 14 章  Google 地圖與定位服務

14-1-2 使用定位服務 - 我在哪裡步驟四:在 AndroidManifest.xml 新增權限因為需要使用定位服務,所以在

AndroidManifest.xml 檔新增 2 個權限, ACCESS_COURSE_LOCATION 是網路定位服務, ACCESS_FINE_LOCATION是 GPS 定位服務,如下所示:<uses-permission android:name= "android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION"/>

Page 20: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標 ( 說明 )

地圖解碼服務( Geocoding Services )可以從位置名稱、郵遞區號等資訊來找出經緯度座標,或反過來,從經緯度座標找出位置名稱或地址。

Android 是使用 Geocoder 類別來處理座標轉換,相關方法的說明,如下表所示:

方法 說明

getFromLocation() 將經緯度座標轉換成地址資訊,目前台灣只能轉換成所屬鄉鎮區和郵遞區號

getFromLocationName() 將位置名稱或地址轉換成經緯度座標

Page 21: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟一:開啟和執行 Android 專案 請啟動 Eclipse IDE 開啟 Android 專案 Ch14_2 ,內含 1個 Java 類別檔和版面配置檔 main.xml ,因為Android模擬器不支援地圖解碼服務,筆者是使用2.3 版的實機來測試,其執行結果如下圖所示:

Page 22: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟二:建立找出景點座標使用介面的版面配置 -1

找出景點座標使用介面的版面配置是定義在 main.xml 檔,使用 LinearLayout 垂直編排數個水平的 LinearLayout ,內含 TextView和 EditText 元件輸入座標和景點名稱,如下所示:<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 緯度 (Latitude):"/>

Page 23: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟二:建立找出景點座標使用介面的版面配置 -2

<EditText android:id="@+id/txtLat" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="25.047924" android:inputType="numberDecimal"/></LinearLayout>

EditText 元件輸入緯度,另有 2 個是輸入經度和景點名稱,查詢結果的地址是顯示在 Spinner 元件,如下所示:<Spinner android:id="@+id/addresslist" android:layout_width="fill_parent" android:layout_height="wrap_content"/>

至於查詢的經緯度是顯示在 TextView 元件, Button 元件button1~3 的事件處理方法為 button1~3_Click() 。

Page 24: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -1

在 Ch14_2Activity 活動類別的開頭宣告成員的ArrayAdapter和 Geocoder 等物件變數,如下所示:public class Ch14_2Activity extends Activity { private final int maxResult = 3; private String addressList[] = new String[maxResult]; private ArrayAdapter<String> adapter; private TextView output; private Geocoder geocoder; private EditText lat, lon; …}

Page 25: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -2

onCreate() 方法 在覆寫的 onCreate() 方法載入版面配置後,可以取得

EditText 物件來取得輸入座標,如下所示:@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lat = (EditText) findViewById(R.id.txtLat); lon = (EditText) findViewById(R.id.txtLong); output = (TextView)findViewById(R.id.output); geocoder = new Geocoder(this, Locale.TAIWAN);}

Page 26: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -3

button1_Click()事件處理方法 在 button1_Click()事件處理方法將經緯度座標轉換成地址

,首先將經緯度的輸入字串轉換成 float浮點數,如下所示:public void button1_Click(View view) { float latitude = Float.parseFloat(lat.getText().toString()); float longitude = Float.parseFloat(lon.getText().toString()); try { List<Address> listAddress = geocoder.getFromLocation( latitude, longitude, maxResult);

程式碼呼叫 Geocoder 物件的 getFromLocation() 方法取得地址清單的 List 物件,參數依序是緯度、經度和最多傳回的地址數。

Page 27: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -4

如果有傳回地址,就在下方 if 條件的程式區塊建立 ArrayAdapter 結合器物件,然後顯示在 Spinner 元件,如下所示:

if (listAddress != null) { Spinner spinner = (Spinner)findViewById(R.id.addresslist); for (int j = 0; j < maxResult; j++) addressList[j] = "N/A"; int index = 0; for (int j = 0; j < maxResult; j++) { Address findAddress = listAddress.get(j); StringBuilder strAddress = new StringBuilder(); for (int i = 0; i < findAddress.getMaxAddressLineIndex(); i++) { String str = findAddress.getAddressLine(i); strAddress.append(str).append("\n"); } if (strAddress.length() > 0) { addressList[index++] = strAddress.toString(); } }

Page 28: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -5

在建立 addressList[]陣列後,可以將此陣列建立成 ArrayAdapter 結合器物件,如下所示:

adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, addressList); adapter.setDropDownViewResource(android.R.layout. simple_spinner_dropdown_item); spinner.setAdapter(adapter); } else { output.setText("注意 : 沒有傳回地址資料 !"); } } catch (Exception ex) { output.setText("錯誤 :" + ex.toString()); }}

Page 29: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -6

button2_Click()事件處理方法 在 button2_Click()事件處理方法將地址轉換成經緯度座標,首先取得使用者在 EditText 元件輸入的名稱,如下所示:public void button2_Click(View view) { EditText address = (EditText) findViewById(R.id.txtAddress); String addressName = address.getText().toString(); try { List<Address> listGPSAddress = geocoder. getFromLocationName(addressName, 1);

上述程式碼呼叫 Geocoder 物件的 getFromLocationName() 方法搜尋經緯度座標,第 1 個參數是名稱,第 2 個參數最多傳回幾個座標。

Page 30: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -7

如果有傳回座標,就取出緯度和經度且將它顯示出來,如下所示: if (listGPSAddress != null) { double latitude = listGPSAddress.get(0).getLatitude(); double longitude = listGPSAddress.get(0).getLongitude(); output.setText(" 緯度 : " + latitude + "\n 經度 : " + longitude); lat.setText(String.valueOf(latitude)); lon.setText(String.valueOf(longitude)); } } catch (Exception ex) { output.setText("錯誤 :" + ex.toString()); }}

Page 31: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟三:建立 Activity 活動類別找出景點座標 -8

button3_Click()事件處理方法 button3_Click()事件處理方法使用 Intent 物件啟動

Google 地圖,它和第 14-1-2節的 button1_Click()事件處理方法相同,筆者就不重複說明。

Page 32: 第 14 章  Google 地圖與定位服務

14-2 地圖解碼服務 - 找出景點座標步驟四:在 AndroidManifest.xml 新增存取 Internet 權限

找出景點座標因為需要連線 Internet ,所以在AndroidManifest.xml 檔需要新增 INTERNET權限,如下所示:<uses-permission

android:name="android.permission.INTERNET"/>

Page 33: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達

GPS 景點防撞雷達是本地服務與定位服務的應用,可以在行動裝置接近輸入的景點座標時,發出警告,其他可能的應用包含危險區域警示,和標示目標區域來檢查是否已經到達其範圍之中。

Page 34: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟一:開啟和執行 Android 專案 請啟動 Eclipse IDE 開啟 Android 專案 Ch14_3 ,內含 3個 Java 類別檔和版面配置檔 main.xml ,在執行前,請先在 Android模擬器新增 GPS硬體支援,然後就可以執行此專案,其執行結果如下圖所示:

Page 35: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟二:建立 GPS 景點防撞雷達使用介面的版面配置

GPS 景點防撞雷達使用介面的版面配置是定義在 main.xml 檔,使用LinearLayout 垂直編排 3 個水平 LinearLayout ,內含 TextView和EditText 元件輸入座標和 Button 按鈕元件,如下所示:

<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 經度 (Longitude):"/> <EditText android:id="@+id/txtLong" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="121.51617" android:inputType="numberDecimal"/> </LinearLayout>

Page 36: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟三:建立 Activity 活動類別的事件處理方法 -1

在 Ch14_3Activity 活動類別的開頭宣告成員的EditText和 TextView 物件變數,如下所示:public class Ch14_3Activity extends Activity { private EditText lat, lon; private TextView output; …}

Page 37: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟三:建立 Activity 活動類別的事件處理方法 -2

onCreate() 方法 在覆寫的 onCreate() 方法載入版面配置後,可以取得

EditText和 TextView 物件,如下所示:@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lat = (EditText) findViewById(R.id.txtLat); lon = (EditText) findViewById(R.id.txtLong); output = (TextView) findViewById(R.id.output);}

Page 38: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟三:建立 Activity 活動類別的事件處理方法 -3

start_Click()事件處理方法 在 start_Click()事件處理方法建立 Intent 物件後,呼叫

startService() 方法啟動 GPSService.class 服務,並且傳遞經緯度座標 LATITUDE和 LONGITUDE ,如下所示:public void start_Click(View view) { float latitude = Float.parseFloat(lat.getText().toString()); float longitude = Float.parseFloat(lon.getText().toString()); Intent intent = new Intent(this, GPSService.class); intent.putExtra("LATITUDE", latitude); intent.putExtra("LONGITUDE", longitude); startService(intent);

output.setText(" 服務啟動中 ...");}

Page 39: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟三:建立 Activity 活動類別的事件處理方法 -4

stop_Click()事件處理方法在 stop_Click()事件處理方法建立 Intent 物件後,呼叫 stopService() 方法停止 GPSService.class 服務,如下所示:public void stop_Click(View view) { Intent intent = new Intent(this, GPSService.class); stopService(intent); output.setText(" 服務停止中 ...");}

Page 40: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟三:建立 Activity 活動類別的事件處理方法 -5

finish_Click()事件處理方法在 finish_Click()事件處理方法呼叫 finish() 方法結束活動,如下所示:public void finish_Click(View view) { finish();}

Page 41: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟四:建立 GPSService 服務類別 -1 在 GPSService 服務類別使用 GPS 定位服務來檢查是否距離景點 100 公尺以內,如果是,送出廣播給 GPSReceiver 類別。

GPSService 服務類別繼承 Service 類別且實作 LocationListener介面,在開頭宣告 LocationManager 物件變數,如下所示:public class GPSService extends Service implements LocationListener { private LocationManager manager; private boolean isInArea; private double latitude, longitude; ….}

Page 42: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟四:建立 GPSService 服務類別 -2

onCreate() 方法 在 onCreate() 方法取得 LOCATION_SERVICE 系統服務的

LocationManager 物件後,註冊類別本身為傾聽者物件來定時更新位置資訊,如下所示:@Overridepublic void onCreate() { manager = (LocationManager) getSystemService(LOCATION_SERVICE); manager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 10000, 1, this); isInArea = false;}

Page 43: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟四:建立 GPSService 服務類別 -3onStartCommand() 方法 在 onStartCommand() 方法取得 Intent 物件傳遞的經緯度座標

LATITUDE和 LONGITUDE ,如下所示:@Overridepublic int onStartCommand(Intent intent, int flags, int startId) { latitude = (double) intent.getFloatExtra( "LATITUDE", 40.422005f); longitude = (double) intent.getFloatExtra( "LONGITUDE", -122.084095f); Log.d("GPSService", "lat/long: "+latitude+": "+longitude); return START_STICKY;}

Page 44: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟四:建立 GPSService 服務類別 -4

onDestroy() 方法在 onDestroy() 方法呼叫 removeUpdates() 方法移除定位服務的位置更新,如下所示:@Overridepublic void onDestroy() { manager.removeUpdates(this);}

Page 45: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟四:建立 GPSService 服務類別 -5

onBind() 方法 onBind() 方法並沒有使用,但是因為是抽象方法

,類別一定要實作,所以傳回 null ,如下所示:@Overridepublic IBinder onBind(Intent intent) { return null;}

Page 46: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟四:建立 GPSService 服務類別 -6實作 LocationListener 介面的 4 個方法 因為 GPSService 服務類別本身是實作 LocationListener 介面的傾聽者物

件,所以需要實作介面的 4 個方法,不過,我們只有使用onLocationChanged() 方法,如下所示:@Overridepublic void onLocationChanged(Location current) { if (current == null) return; Location dest = new Location(current); dest.setLatitude(latitude); dest.setLongitude(longitude); float distance = current.distanceTo(dest); Log.d("Ch14_3", " 距離 : " + distance);

程式碼在建立目標座標的 Location 物件後,呼叫參數 current 目前Location 物件的 distanceTo() 方法,參數是目標的 Location 物件,可以計算 2 個座標之間的距離是多少公尺。

Page 47: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟四:建立 GPSService 服務類別 -7 在下方 if 條件檢查距離是否小於 100 公尺,如果是,建立 Intent 物件送出廣播,如下所示:

if (distance < 100.0) { if (isInArea == false) { Intent intent = new Intent( "android.broadcast.LOCATION"); sendBroadcast(intent); isInArea = true; } } else { isInArea = false; }}

Page 48: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟五:建立 GPSReceiver 廣播接收器類別 GPSReceiver廣播接收器類別是用來接收 GPSService 服務送出的

android.broadcast.LOCATION廣播,可以使用 Toast 類別顯示訊息,和振動提醒已經接近景點範圍,如下所示:public class GPSReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "已經接近景點範圍 ", Toast.LENGTH_LONG).show(); Vibrator vibrator = (Vibrator) context.getSystemService( Context.VIBRATOR_SERVICE); vibrator.vibrate(500); // 半秒 }}

Page 49: 第 14 章  Google 地圖與定位服務

14-3 本地服務與定位應用 -GPS 景點防撞雷達步驟六:在 AndroidManifest.xml 註冊元件和新增權限

GPSService 服務和 GPSReceiver廣播接收器需要在 AndroidManifest.xml檔註冊,可以處理 android.broadcast.LOCATION 的廣播,如下所示:<receiver android:name=".GPSReceiver"> <intent-filter> <action android:name="android.broadcast.LOCATION" /> </intent-filter></receiver><service android:name=".GPSService"/>

GPS 景點防撞雷達需要使用定位服務和振動,所以需要新增 2 個權限,如下所示:<uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION"/><uses-permission android:name="android.permission.VIBRATE"/>

Page 50: 第 14 章  Google 地圖與定位服務

14-4 使用 Google Maps API-My 地圖

14-4-1 取得 Google Maps API金鑰 14-4-2 使用 MapView 元件和 MapActivity 類別 -My

地圖

Page 51: 第 14 章  Google 地圖與定位服務

14-4 使用 Google Maps API-My 地圖

Google Map (地圖)是一套內建 Android 作業系統的應用程式,在本節前我們已經使用 Intent 物件啟動地圖應用程式,顯示指定經緯度座標的地圖。

在實務上,我們可能需要將 Google Map 內嵌在Android 應用程式來建立所需的應用,不過,因為Google Map 並不包含在 Android SDK ,請注意!我們需要取得 Google Maps API金鑰,和在 Build Target選 Google API ,才能在 Android 應用程式使用 Google Map 。

Page 52: 第 14 章  Google 地圖與定位服務

14-4-1 取得 Google Maps API 金鑰

在將 Google Map整合至你的 Android 應用程式之前,我們需要先取得免費的 Google Maps API金鑰。對於在 Android模擬器或連接開發電腦實機上測試執行應用程式所需的金鑰,我們是使用 SDK偵錯憑證( Debug Certificate )來申請金鑰。• 步驟一:取得 SDK偵錯憑證的路徑• 步驟二:取出申請所需MD5認證指紋碼 • 步驟三:上網申請金鑰

Page 53: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My 地圖 在取得 Google Maps API金鑰後,我們就可以使用

MapView 元件和繼承MapActivity抽象類別來建立自己的地圖程式, My 地圖是使用 GPS 定位服務,當位置座標改變時,馬上更新地圖顯示的位置。

Page 54: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟一:開啟和執行 Android 專案 請啟動 Eclipse IDE 開啟 Android 專案 Ch14_4_2 ,然後就可以執行此專案,內含 1個 Java 類別檔和版面配置檔 main.xml ,其執行結果如下圖所示:

Page 55: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟二:建立 MapView 元件的版面配置 My 地圖使用介面的版面配置是定義在 main.xml 檔,使用

LinearLayout 垂直編排 1個 TextView和MapView 元件,如下所示:<TextView android:id="@+id/output" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text=" 在地圖上顯示你的位置 "/><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="0JNEnTMsG9nVME5Lbx2LxFQr1zTh65aObDEbzsw"/>

Page 56: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務1 在 Ch14_4_2Activity 活動類別因為使用 MapView 元件,所

以需要繼承MapActivity抽象類別,而不是 Activity 類別,因為 MapActivity抽象類別已經實作一些顯示 MapView 元件所需的方法,如下所示:public class Ch14_4_2Activity extends MapActivity { private MapView mapView; private TextView output; private MapController mc; private GeoPoint gp; private LocationManager manager; private LocationListener locationListener; …}

Page 57: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務2onCreate() 方法 在覆寫的 onCreate() 方法載入版面配置後,就可以取得系統服務的

LocationManager 物件, if 條件檢查是否有啟用 GPS ,如下所示:@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); output = (TextView) findViewById(R.id.output); manager = (LocationManager) getSystemService(LOCATION_SERVICE); if (!manager.isProviderEnabled( LocationManager.GPS_PROVIDER)) { … }

上述 if 條件的程式碼和第 14-1-2節的 onCreate() 方法相同,筆者就不重複說明。

Page 58: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務3 在下方取得 MapView 物件後,呼叫

setBuiltInZoomControls() 方法,參數 true 是使用內建縮放控制,如下所示: mapView = (MapView)

findViewById(R.id.mapView); mapView.setBuiltInZoomControls(true); mapView.setSatellite(false);

setSatellite() 方法可以指定成衛星空照圖的顯示方式,因為參數是 false ,就是使用標準方式來顯示。

Page 59: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務4 在下方呼叫 getController() 方法取得 MapController

物件後,取得預設的經緯度座標 lng和 lat ,如下所示: mc = mapView.getController(); double lat = Double.parseDouble("25.06924"); double lng = Double.parseDouble("121.51617"); gp = new GeoPoint((int) (lat * 1E6),(int) (lng * 1E6)); mc.animateTo(gp); mc.setZoom(18);}

Page 60: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務5onResume() 方法 在覆寫的 onResume() 方法建立定位服務的傾聽者物件,即之後的內層類別

GPSLocationListener ,在設定更新位置頻率的條件後,呼叫requestLocationUpdates() 方法註冊傾聽者物件來周期性回報目前的位置,如下所示:

@Overrideprotected void onResume() { super.onResume(); locationListener = new GPSLocationListener(); int minTime = 1000; // 毫秒 loat minDistance = 1; // 公尺 manager.requestLocationUpdates( LocationManager.GPS_PROVIDER, minTime, minDistance,locationListener); manager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, minTime, minDistance,locationListener);}

Page 61: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務6實作 LocationListener 介面的內層類別 實作 LocationListener 介面的內層類別就是用來建立定位服務更新位置的傾聽者物件,

介面需實作 4 個方法,不過,我們只有使用 onLocationChanged() 方法,如下所示:class GPSLocationListener implements LocationListener { @Override public void onLocationChanged(Location current) { double lat, lng; if (current != null) { lat = current.getLatitude(); lng = current.getLongitude(); Toast.makeText(Ch14_4_2Activity.this, " 經緯度座標變更 ....", Toast.LENGTH_SHORT).show(); output.setText(" 緯度 : " + lat + " 經度 : " + lng); gp = new GeoPoint((int) (lat * 1E6),(int) (lng * 1E6)); mc.animateTo(gp); mc.setZoom(18); } }

Page 62: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務7 後面的 3 個實作方法並沒有使用,如下所示:

@Override public void onProviderDisabled(String provider) { } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { }}

Page 63: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟三:建立 MapActivity 活動類別和使用定位服務8isRouteDisplayed() 方法因為 MapActivity 是抽象類別,繼承的類別一定要

實作 isRouteDisplayed()抽象方法,傳回是否顯示任何規劃路徑,沒有傳回 false ,如下所示:@Overrideprotected boolean isRouteDisplayed() { return false;}

Page 64: 第 14 章  Google 地圖與定位服務

14-4-2 使用 MapView 元件和 MapActivity 類別 -My地圖步驟四:在 AndroidManifest.xml 註冊函數庫和新增權限 因為 Google Maps API 不是 Android 內建函數庫,所以當

Android 應用程式使用 Google Maps API時,我們需要在application 元素新增 uses-library 子元素,讓應用程式可以使用此函數庫,如下所示:<uses-library android:name="com.google.android.maps"/>

My 地圖需要存取網路和使用定位服務,所以需要新增 2個權限,如下所示:<uses-permission

android:name="android.permission.INTERNET"/><uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION"/>

Page 65: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤

實務上,我們不只可以使用 MapView 元件和MapActivity 類別來建立地圖程式,更可以在地圖上作記號,例如:標記加油站、停車場位置或個人行蹤等。

標記 Google 地圖是使用 Overlay 類別,它如同是一片透明投影片,可以讓我們在上面作記號,然後如同圖層般一層一層疊在地圖上。

Page 66: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟一:開啟和執行 Android 專案 請啟動 Eclipse IDE 開啟

Android 專案 Ch14_5 ,就可以執行此專案,內含 3個 Java 類別檔和 2 個版面配置檔,其執行結果如下圖所示:

Page 67: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟二:建立主活動使用介面的版面配置 -1 主活動使用介面的版面配置是定義在 main.xml 檔,使用

LinearLayout 垂直編排 2個 TextView 元件和 1 個水平的LinearLayout ,內含 2個 Button 元件,如下所示:<TextView android:id="@+id/output" android:layout_width="fill_parent" android:layout_height="wrap_content"/><LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"

Page 68: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟二:建立主活動使用介面的版面配置 -2

android:text=" 顯示 Google 地圖 " android:onClick="button1_Click"/> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 追蹤個人行蹤 " android:onClick="button2_Click"/></LinearLayout><TextView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="wrap_content"/>

Page 69: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -1

在 Ch14_5Activity 活動類別的開頭宣告常數與成員變數,使用 GPLat[]和 GPLng[]陣列儲存個人行蹤的座標,如下所示:public class Ch14_5Activity extends Activity { private final int MAX_RECORDS = 10; private LocationManager manager; private Location currentLocation; private String best; private int index = 0, count = 0; private double[] GPLat = new double[MAX_RECORDS]; private double[] GPLng = new double[MAX_RECORDS]; …}

Page 70: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -2

onCreate() 方法 在覆寫的 onCreate() 方法載入版面配置後,取得

系統服務的 LocationManager 物件,如下所示:@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); manager = (LocationManager) getSystemService(LOCATION_SERVICE);}

Page 71: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -3

onResume() 方法 onResume() 方法和第 14-1-2節步驟三的同名方法相同,只是更新位置頻率的條件不同,如下所示:int minTime = 5000; // 毫秒float minDistance = 15; // 公尺

Page 72: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -4

onPause() 方法 在覆寫 onPause() 方法呼叫 removeUpdates() 方法

取消周期更新位置,此方法和第 14-1-2節步驟三的同名方法相同。

Page 73: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -5

updatePosition() 方法 在自訂 updatePosition() 方法更新 TextView 元件顯示的位置資訊和個人行蹤的

座標清單,如下所示:@Overrideprivate void updatePosition() { TextView output, list; String str = " 最近個人行蹤的座標清單 :\n"; output = (TextView) findViewById(R.id.output); list = (TextView) findViewById(R.id.list); if (currentLocation == null) { output.setText(" 取得定位資訊中 ..."); } else { output.setText(getLocationInfo(currentLocation)); for (int i = 0; i < MAX_RECORDS; i++) { if (GPLat[i] != 0.0) str += GPLat[i] + "/" + GPLng[i] +"\n"; } list.setText(str); }}

Page 74: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -6

LocationListener傾聽者物件在 requestLocationUpdates() 方法需要註冊定位服

務的傾聽者物件,即使用匿名內層類別實作LocationListener 介面來建立此物件,此物件和第14-1-2節步驟三的同名物件相同。

Page 75: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -7

getLocationInfo() 方法 在自訂 getLocationInfo() 方法可以從參數 Loaction 物件取得定位資訊

和檢查是否需要儲存個人行蹤的座標,如下所示:public String getLocationInfo(Location location) { boolean isSave = true; double lat, lng; lat = location.getLatitude(); lng = location.getLongitude(); StringBuffer str = new StringBuffer(); str.append(" 定位提供者 (Provider): "+ location.getProvider()); str.append("\n 緯度 (Latitude): " + Double.toString(lat)); str.append("\n 經度 (Longitude): " + Double.toString(lng));

Page 76: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -8

如果是,就可以計算第 2 個座標和前一個座標的距離,首先建立目地 GPS 座標的 Location 物件,如下所示:

if (count >= 1) { Location dest = new Location(location); int preIndex = index - 1; if (preIndex < 0 ) preIndex = GPLat.length - 1; dest.setLatitude(GPLat[preIndex]); dest.setLongitude(GPLng[preIndex]);

在下方使用 distanceTo() 方法計算與目地座標的距離,如果距離小於 20 公尺就不儲存,此時旗標變數 isSave 的值為 false ,如下所示:

float distance = location.distanceTo(dest); Toast.makeText(this, " 距離 : " + distance + " 公尺 ", Toast.LENGTH_SHORT).show(); if (distance < 20.0) isSave = false; } if (isSave) {

Page 77: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -9

上述 if 條件的 isSave旗標變數值為 true ,表示需要新增座標, count 變數記錄共儲存幾個座標,如果超過陣列尺寸,就指定為陣列尺寸的個數,如下所示: GPLat[index] = lat; GPLng[index] = lng; count++; if (count >= MAX_RECORDS) count = MAX_RECORDS; index++; if (index >= MAX_RECORDS) index = 0; } return str.toString();}

Page 78: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -10

button1_Click()事件處理方法 button1_Click()事件處理方法可以依據目前的位置

座標來啟動 Google 地圖,它和第 14-1-2節步驟三的同名方法相同。

Page 79: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟三:建立 Activity 主活動類別記錄座標清單 -11

button2_Click()事件處理方法 button2_Click()事件處理方法可以在 MapView 元件顯示個

人行蹤,這是使用 Intent 物件啟動 MyMapActivity 活動類別,附件是個人行蹤座標的 2 個陣列,和座標數的 count變數值,如下所示:public void button2_Click(View view) { Intent mapView = new Intent(this, MyMapActivity.class); mapView.putExtra("GPSLATITUDE", GPLat); mapView.putExtra("GPSLONGITUDE", GPLng); mapView.putExtra("MAX_INDEX", count); startActivity(mapView); }

Page 80: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟四:建立 MapView 元件的版面配置 MyMapActivity 活動類別的版面配置是定義在 map.xml 檔

,使用 LinearLayout 垂直編排 1個MapView 元件,如下所示:<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="0JNEnTMsG9nVME5Lbx2LxFQr1zTh65aObDEbzsw"/>

Page 81: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟五:建立 MyMapActivity 活動類別來標記地圖 -1 MyMapActivity 活動類別是繼承MapActivity抽象

類別,在類別開頭宣告 MapView和MapController物件變數,如下所示:public class MyMapActivity extends MapActivity { private MapView mapView; private MapController mc; …}

Page 82: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟五:建立 MyMapActivity 活動類別來標記地圖 -2onCreate() 方法 在覆寫的 onCreate() 方法載入版面配置後,就可以取得

MapView 元件和 MapController 物件,如下所示:@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.map); mapView = (MapView)findViewById(R.id.mapView); mc = mapView.getController(); ArrayList<GeoPoint> locations = new ArrayList<GeoPoint>(); ArrayList<Drawable> images = new ArrayList<Drawable>(); double[] GPLat, GPLng; int max_index;

Page 83: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟五:建立 MyMapActivity 活動類別來標記地圖 -3 然後在下方取得 Intent 物件傳遞的座標陣列,如下所示:

GPLat = getIntent().getDoubleArrayExtra("GPSLATITUDE"); GPLng = getIntent().getDoubleArrayExtra("GPSLONGITUDE"); max_index = getIntent().getIntExtra("MAX_INDEX", 10); for (int i = 0; i < max_index; i++) { int gpLat, gpLng; gpLat = (int) (GPLat[i]*1000000); gpLng = (int) (GPLng[i]*1000000); locations.add(new GeoPoint(gpLat,gpLng)); images.add(getResources().getDrawable(R.drawable.pin)); }

for迴圈一一將陣列座標轉換成 GeoPoint 座標後,新增至 ArrayList集合物件,標記圖示都是同一個 pin.png ,換句話說,如果需要,每一個座標可以使用不同的標記圖示。

Page 84: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟五:建立 MyMapActivity 活動類別來標記地圖 -4 在下方建立 LocationOverlay 物件,其宣告在下一步驟,這

是一個繼承 ItemizedOverlay 類別的物件,建構子參數是預設標記圖示和 Context 物件 this ,如下所示: LocationOverlay myOverlay = new LocationOverlay( getResources().getDrawable(R.drawable.icon), this); myOverlay.setItems(locations, images); mapView.getOverlays().add(myOverlay);

上述程式碼呼叫 setItems() 方法指定標記的座標和圖示的ArrayList 物件後,呼叫 MapView 物件的 getOverlays() 方法取得圖層 Overlay的 List集合物件,即可呼叫 add() 方法新增 Overlay 物件。

Page 85: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟五:建立 MyMapActivity 活動類別來標記地圖 -5

最後在下方指定 MapView參數為內建縮放控制、衛星空照圖顯示,和使用 MapController 物件指定地圖置中和放大 15 ,如下所示: mapView.setBuiltInZoomControls(true); mapView.setSatellite(true); mc.setCenter(locations.get(0)); mc.setZoom(15);}

Page 86: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟五:建立 MyMapActivity 活動類別來標記地圖 -6

isRouteDisplayed() 方法繼承類別一定要實作 isRouteDisplayed()抽象方法

,傳回是否顯示任何規劃路徑,沒有傳回 false ,如下所示:@Overrideprotected boolean isRouteDisplayed() { return false;}

Page 87: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟六:建立 LocationOverlay 類別 -1 LocationOverlay 類別繼承 ItemizedOverlay 類別,這是一種

項目化的 Overlay 類別,可以使用 List集合物件儲存多個GeoPoint 座標和標記圖示,以便在 Google 地圖上同時使用不同圖示來標示多個座標。

在 LocationOverlay 類別開頭宣告 List集合物件變數myItems和 myMarkers ,如下所示:public class LocationOverlay extends

ItemizedOverlay<OverlayItem> { private List<GeoPoint> myItems; private List<Drawable> myMarkers; private Context context; …}

Page 88: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟六:建立 LocationOverlay 類別 -2

建構子 在類別建構子呼叫父類別的建構子,參數是預設

標示圖示,然後指定成員物件變數 context 的值,如下所示:public LocationOverlay(Drawable defaultMarker, Context

context) { super(boundCenterBottom(defaultMarker)); this.context = context;}

Page 89: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟六:建立 LocationOverlay 類別 -3

setItems() 方法 在自訂 setItems() 方法指定各項目的座標和標記圖

示,參數是 ArrayList集合物件,如下所示:public void setItems(ArrayList<GeoPoint> items, ArrayList<Drawable> drawables) { myItems = items; myMarkers = drawables; populate(); }

Page 90: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟六:建立 LocationOverlay 類別 -4

createItem() 方法 在實作 createItem()抽象方法建立 OverlayItem 項目物件,

和呼叫 setMarker() 方法指定標記圖示,方法參數是索引,此方法是由 populate() 方法來呼叫,如下所示:@Overrideprotected OverlayItem createItem(int i) { OverlayItem item = new OverlayItem( myItems.get(i), null, null); item.setMarker(boundCenterBottom( myMarkers.get(i))); return item;}

Page 91: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟六:建立 LocationOverlay 類別 -4

size() 方法 在實作 size()抽象方法傳回項目數,如下所示:

@Overridepublic int size() { return myItems.size();}

Page 92: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟六:建立 LocationOverlay 類別 -5

onTap() 方法 覆寫 onTap() 方法來處理指定項目的 Tap事件,也就是說

,觸摸一下標記圖示,可以使用 Toast 類別顯示此點的座標,如下所示:@Override protected boolean onTap(int i) { GeoPoint gp = myItems.get(i); Toast.makeText(context, " 座標 : "+ gp.getLatitudeE6() / 1E6 + "," + gp.getLongitudeE6() /1E6 , Toast.LENGTH_SHORT).show(); return true; }

Page 93: 第 14 章  Google 地圖與定位服務

14-5 標記 Google 地圖 - 追蹤個人行蹤步驟七:在 AndroidManifest.xml 註冊函數庫和新增權限

因為 Google Maps API 不是 Android 內建函數庫,所以當Android 應用程式使用 Google Maps API時,我們需要在application 元素新增 uses-library 子元素,讓應用程式可以使用此函數庫,如下所示:<uses-library android:name="com.google.android.maps"/>

程式需要存取網路和使用定位服務,所以需要新增 3 個權限,如下所示:<uses-permission

android:name="android.permission.INTERNET"/><uses-permission android:name= "android.permission.ACCESS_COARSE_LOCATION"/><uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION"/>

Page 94: 第 14 章  Google 地圖與定位服務