Android 智 慧 型 手 機 程 式 設 計 程 式 設 計 與 應 用 班 Android Google Maps 建 國 科 技 大 學 資 管 系 饒 瑞 佶 2012/4 V1 2012/8 V2
Google Maps Reference: http://developer.android.com/resources/tutorials/views/hello-mapview.html 取 得 Google Map API Step1: 先 進 入 JDK 目 錄
Google Maps 透 過 keytool.exe 建 立 認 證 指 紋 需 要 debug_keystore 路 徑
debug_keystore 路 徑 Google Maps
Google Maps 輸 入 keytool list alias androiddebugkey keystore C:\Documents and Settings\Administrator\.android\debug.keystore storepass android keypass android
產 生 認 證 指 紋 Google Maps
Google Maps 進 入 Google Map API Key 申 請 頁 面 http://code.google.com/intl/zh-tw/android/addons/google-apis/maps-api-signup.html 輸 入 認 證 指 紋 碼
Google Maps 進 入 Google Map API Key 申 請 頁 面 http://code.google.com/intl/zh-tw/android/addons/google-apis/maps-api-signup.html
產 生 出 API 金 鑰 Google Maps 0O7bGO2vQxBc90bpYbJ8PnSjJapePPkrSGRvP3 A 加 入 main.xml <com.google.android.maps.mapview android:layout_width="fill_parent" android:layout_height="fill_parent" android:apikey="0o7bgo2vqxbc90bpybj8pnsj JapePPkrSGRvP3A" />
main.xml Google Maps
Google Maps 建 立 新 專 案 : HelloMaps 沒 有 Google APIs target
Google Maps 如 果 沒 有 Google APIs target 請 選 擇 Available packages 進 行 安 裝
Google Maps 安 裝 完 Google APIs target 畫 面
建 立 新 專 案 : HelloMaps Google Maps
顯 示 Google Maps 地 圖 加 入 改 成 MapActivity 加 入
Google Maps AVD 也 要 對 應 具 備 Google APIs 功 能
Google Maps 增 加 <uses-permission android:name="android.permission.internet" /> 在 <application> 裡 頭 增 加 <uses-library android:name="com.google.android.maps" /> 資 訊
Google Maps
在 Google Maps 上 加 標 示 需 要 一 個 overlay class, 做 堆 疊 圖 層 之 用
import java.util.arraylist; import android.app.alertdialog; import android.content.context; import android.graphics.drawable.drawable; import com.google.android.maps.itemizedoverlay; import com.google.android.maps.overlayitem; MapsOverlay public class MapsOverlay extends ItemizedOverlay<OverlayItem> { private ArrayList<OverlayItem> mapoverlays = new ArrayList<OverlayItem>(); private Context context; public MapsOverlay(Drawable defaultmarker) { super(boundcenterbottom(defaultmarker)); public MapsOverlay(Drawable defaultmarker, Context context) { this(defaultmarker); this.context = context; @Override protected OverlayItem createitem(int i) { return mapoverlays.get(i); @Override public int size() { return mapoverlays.size(); @Override protected boolean ontap(int index) { OverlayItem item = mapoverlays.get(index); AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.settitle(item.gettitle()); dialog.setmessage(item.getsnippet()); dialog.show(); return true; public void addoverlay(overlayitem overlay) { mapoverlays.add(overlay); this.populate();
Main.xml 決 定 地 圖 能 不 能 互 動 決 定 View 顯 示 方 式 需 要 與 layout_width 或 layout_height 一 起 使 用 加 入 這 段 來 切 換 地 圖 種 類
layout_weight 改 變 看 看 改 變 看 看 改 變 看 看 改 變 看 看 改 變 看 看 改 變 看 看
HelloMaps 給 定 一 個 座 標 ( 未 來 可 以 來 自 於 GPS) 坐 標 圖 示 在 給 定 座 標 上 加 圖 示 切 換 成 衛 星 圖 圖 示 按 下 時 顯 示 的 資 訊 切 換 成 標 準 地 圖
試 試 改 變 圖 示
地 址 轉 座 標 try { inputaddress=(edittext)findviewbyid(r.id.edittext1); Geocoder geocoder = new Geocoder(Maps1Activity.this, Locale.getDefault()); List<Address> georesults = geocoder.getfromlocationname(inputaddress.gettext().tostring(), 5); while (georesults.size()==0) { georesults = geocoder.getfromlocationname(inputaddress.gettext().tostring(), 5); if (georesults.size()>0) { Address addr = georesults.get(0); Double latitude = addr.getlatitude() * 1E6; Double longitude = addr.getlongitude() * 1E6; tv1.settext(latitude + "/" + longitude); showlocation((int) (addr.getlatitude() * 1E6),(int) (addr.getlongitude() * 1E6)); catch (Exception e) { tv1.settext("convert error");
AVD 多 數 執 行 有 問 題, 最 好 使 用 手 機 測 試 1600 Amphitheatre Parkway, Mountain View, CA Android 2.2
輸 入 地 址 轉 換 地 址 成 座 標 座 標 顯 示 座 標 點
不 用 註 冊 Google Maps API 也 可 以 使 用 Intent
建 立 新 專 案 : IntentMaps 利 用 Intent 玩 Google Maps
顯 示 Google Maps 地 圖 要 取 消
利 用 Intent 玩 Google Maps AVD 也 要 對 應 具 備 Google APIs 功 能
利 用 Intent 玩 Google Maps 增 加 <uses-permission android:name="android.permission.internet" />
利 用 Intent 玩 Google Maps
更 多 Google Maps Google Maps URI 格 式 : geo:latitude,longitude << 沒 有 小 圖 示 geo:0,0?q=latitude,longitude << 出 現 圖 示 geo:latitude,longitude?z=zoom << 目 前 沒 作 用 geo:0,0?q=my+street+address << 出 現 有 註 冊 的 位 置 (my 已 取 消 ) geo:0,0?q=business+near+city Google Streetview URI 格 式 : google.streetview:cbll=lat,lng&cbp=1,yaw,,pitch,zoom&mz=mapzoom Uri uri=uri.parse("google.streetview:cbll=46.813812,-71.207378&cbp=1,99.56,,1,- 5.27&mz=21"); 只 支 援 美 加 地 區
更 多 Google Maps 顯 示 地 圖 Uri uri = Uri.parse("geo:38.899533,-77.036476"); Intent it = new Intent(Intent.ACTION_VIEW, uri); startactivity(it); 路 徑 規 劃 Uri uri = Uri.parse("http://maps.google.com/maps? f=d&saddr=startlat%20startlng&daddr=endlat%20endlng&hl=en"); Intent it = new Intent(Intent.ACTION_VIEW, uri); startactivity(it); //where startlat, startlng, endlat, endlng are a long with 6 decimals like: 50.123456
GPS
AndroidManiFest.xml 建 立 一 個 新 專 案 HelloGPS 需 要 開 放 以 下 權 限 <uses-permission android:name="android.permission.access_coarse_location" ></uses-permission> <uses-permission android:name="android.permission.access_fine_location"></u ses-permission>
偵 測 是 否 開 啟 GPS // 如 果 沒 有 開 啟 GPS--------------------- LocationManager status=(locationmanager)(this.getsystemservice(context.location_s ERVICE)); if(status.isproviderenabled(locationmanager.gps_provider) status.isproviderenabled(locationmanager.network_provider)){ else{ // 到 系 統 開 啟 GPS 與 WIFI 服 務 的 畫 面 startactivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); //-------------------- 如 果 沒 有 開 啟 GPS
Android GPS 運 作 方 式 取 得 LocationManager: 判 定 是 否 有 提 供 定 位 服 務 ( 硬 體 GPS 或 WIFI) 建 立 LocationProvider, 設 定 定 位 參 數, 並 同 時 透 過 LocationManager 取 得 座 標 ( 硬 體 軟 體,GPS 或 是 WiFi) 設 定 LocationManager 的 Listener 事 件, 偵 測 事 件 的 改 變 MapController 負 責 控 制 Google Maps
GPS 訊 號 抓 取 主 體 宣 告 GPS 訊 號 擷 取 主 體 沒 有 GPS 時 觸 發
mlocationmanager =(LocationManager)(this.getSystemService(Context.LOCATION_SERVICE)); if(mlocationmanager.isproviderenabled(locationmanager.gps_provider) mlocationmanager.isproviderenabled(locationmanager.network_provider)){ else{ // 到 達 系 統 開 啟 GPS 與 WIFI 服 務 的 畫 面 startactivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); //-------------------- 如 果 沒 有 開 啟 GPS 啟 動 GPS 如 果 沒 有 啟 動 使 用 GPS 服 務, 將 跳 至 設 定 畫 面 /* Provider 初 始 化 */ getlocationprivider(); 要 求 GPS 提 供 服 務 /* 設 定 事 件 的 Listener */ mlocationmanager.requestlocationupdates(mlocationprivider, 2000, 0, mlocationlistener); 設 定 GPS 監 聽 服 務 if(mlocation!=null) // 第 一 次 顯 示 { // 取 得 速 度 double speed=mlocation.getspeed()/1000*60*60; // 原 單 位 是 m/s double altitude = mlocation.getaltitude(); tv_show_gps.settext(" 緯 度 :" + formatgeo(mlocation.getlatitude()) + " 經 度 :" + formatgeo(mlocation.getlongitude()) + " 海 拔 :" + altitude + " m 速 度 :" + formatspeed(speed) + "km/h"); 如 果 有 GPS 訊 號, 顯 示 到 畫 面 上 TextView tv_show_gps; private ProgressDialog MyDialog; private LocationManager mlocationmanager; private String mlocationprivider=""; private Location mlocation; 宣 告 物 件
// 取 得 LocationProvider public void getlocationprivider() { Criteria mcriteria01 = new Criteria(); mcriteria01.setaccuracy(criteria.accuracy_fine); mcriteria01.setaltituderequired(true); // 需 要 高 度 mcriteria01.setbearingrequired(false); mcriteria01.setcostallowed(true); mcriteria01.setpowerrequirement(criteria.power_low); mlocationprivider = mlocationmanager.getbestprovider(mcriteria01, true); mlocation = mlocationmanager.getlastknownlocation(mlocationprivider);
// 偵 測 位 置 改 變 public final LocationListener mlocationlistener = new LocationListener() { public void onlocationchanged(location location) { // 如 果 記 錄 進 行 中, 就 畫 路 線 並 更 新 移 動 距 離 // 取 得 速 度 double speed=location.getspeed()/1000*60*60; // 原 單 位 是 m/s double altitude = location.getaltitude(); tv_show_gps.settext(" 緯 度 :" + formatgeo(location.getlatitude()) + " 經 度 :" + formatgeo(location.getlongitude()) + " 海 拔 :" + altitude + " m 速 度 :" + formatspeed(speed) + "km/h"); MyDialog.dismiss(); // 結 束 進 度 public void onproviderdisabled(string provider) { public void onproviderenabled(string provider) { public void onstatuschanged(string provider,int status,bundle extras) { ; //----------------- 偵 測 位 置 改 變
// 按 BACK 按 鍵 時 關 閉 程 式 @Override public void onbackpressed() { android.os.process.killprocess(android.os.process.mypid()); HelloGPSActivity.this.finish(); // 產 生 定 位 中 視 窗 private void createcancelprogressdialog(string title, String message, String buttontext) { MyDialog = new ProgressDialog(this); MyDialog.setTitle(title); MyDialog.setMessage(message); MyDialog.setButton(buttonText, new DialogInterface.OnClickListener(){ public void onclick(dialoginterface dialog, int which){ // Use either finish() or return() to either close the activity or just the dialog android.os.process.killprocess(android.os.process.mypid()); HelloGPSActivity.this.finish(); return; ); MyDialog.show(); // 顯 示 進 度
// format GPS 座 標 的 方 法 public String formatgeo(double num) { NumberFormat formatter = new DecimalFormat("###.####"); String s=formatter.format(num); return s; // format speed 的 方 法 public String formatspeed(double num) { NumberFormat formatter = new DecimalFormat("###.##"); String s=formatter.format(num); return s;
透 過 ddms 送 出 模 擬 GPS 座 標 到 AVD <uses-permission android:name="android.permission.access_mock_location"/>
GPS 取 得 GPS 訊 號 後, 將 其 顯 示 到 Google Maps 上, 移 動 時, 該 點 會 移 動 抹 除 舊 圖 層, 放 上 新 的 點 顯 示 成 一 個 動 態 路 徑 將 新 的 點 加 入 原 有 圖 層 中, 保 留 所 有 的 點 將 GPS 座 標 記 錄 到 SQLite 資 料 庫, 之 後 可 以 重 新 取 回
取 得 GPS 訊 號 後, 將 其 顯 示 到 Google Maps 上
oncreate 與 宣 告 MapView 物 件 與 圖 層 MapView 對 應 到 圖 層 清 除 圖 層 顯 示 座 標 點
gpsonmaps.xml 來 自 於 Google Maps 認 證 頁
LocationListener 清 除 圖 層 顯 示 座 標 點
showmaps 函 數 負 責 在 圖 層 上 顯 示 GPS 座 標 點
private void showmaps(location location) { Drawable drawable=this.getresources().getdrawable(r.drawable.ic_launcher); MapsOverlay itemizedoverlay=new MapsOverlay(drawable,this); double geolatitude = location.getlatitude()*1e6; double geolongitude = location.getlongitude()*1e6; GeoPoint point=new GeoPoint((int) geolatitude, (int) geolongitude); OverlayItem overlayitem=new OverlayItem(point,"Hello","I'm in Athens, Greece!"); itemizedoverlay.addoverlay(overlayitem); mapoverlays.add(itemizedoverlay); MapController mapcontroller=mapview.getcontroller(); mapcontroller.animateto(point); mapcontroller.setzoom(18); 最 後! 記 得 Activity 要 改 成 MapActivity
取 得 GPS 訊 號 後, 將 其 顯 示 到 Google Maps 上 並 畫 出 軌 跡 從 前 個 範 例 修 改
產 生 MyOverLay 類 別 import android.graphics.canvas; import android.graphics.color; import android.graphics.paint; import android.graphics.point; import android.graphics.rectf; import com.google.android.maps.geopoint; import com.google.android.maps.mapview; import com.google.android.maps.overlay; import com.google.android.maps.projection; public class MyOverLay extends Overlay { private GeoPoint gp1; private GeoPoint gp2; private int mradius=10; private int mode=0; /* 建 構 子, 傳 入 起 點 與 終 點 的 GeoPoint 與 mode */ public MyOverLay(GeoPoint gp1,geopoint gp2,int mode) { this.gp1 = gp1; this.gp2 = gp2; this.mode = mode; @Override public boolean draw (Canvas canvas, MapView mapview, boolean shadow, long when) { Projection projection = mapview.getprojection(); if (shadow == false) { /* 設 定 筆 刷 */ Paint paint = new Paint(); paint.setantialias(true); paint.setcolor(color.blue); // 點 的 顏 色 Point point = new Point(); projection.topixels(gp1, point);
/* mode=1: 建 立 起 點 */ if(mode==1) { /* 定 義 RectF 物 件 */ RectF oval=new RectF(point.x - mradius, point.y - mradius, point.x + mradius, point.y + mradius); /* 繪 製 起 點 的 圓 形 */ canvas.drawoval(oval, paint); /* mode=2: 畫 路 線 */ else if(mode==2) { Point point2 = new Point(); projection.topixels(gp2, point2); paint.setcolor(color.black); // 中 間 路 徑 的 顏 色 paint.setstrokewidth(5); paint.setalpha(120); /* 畫 線 */ canvas.drawline(point.x, point.y, point2.x,point2.y, paint); /* mode=3: 建 立 終 點 */ else if(mode==3) { /* 避 免 誤 差, 先 畫 最 後 一 段 的 路 線 */ Point point2 = new Point(); projection.topixels(gp2, point2); paint.setcolor(color.red); // 結 束 點 的 顏 色 paint.setstrokewidth(5); paint.setalpha(120); canvas.drawline(point.x, point.y, point2.x,point2.y, paint); /* 定 義 RectF 物 件 */ RectF oval=new RectF(point2.x - mradius,point2.y - mradius, point2.x + mradius,point2.y + mradius); /* 繪 製 終 點 的 圓 形 */ paint.setalpha(255); canvas.drawoval(oval, paint); return super.draw(canvas, mapview, shadow, when);
// GPS 座 標 前 後 點 GeoPoint gp1; GeoPoint gp2; MapController mapcontroller; boolean _run; 變 數
修 改 oncreate
btn_streetview.setonclicklistener(new Button.OnClickListener() //strat { @Override public void onclick(view arg0) { // TODO Auto-generated method stub try{ gp1=gp2; resetoverlay(); _run = true; refreshmapview(); setroute(1); // 起 點 catch(exception e){ ); btn_satellitetview.setonclicklistener(new Button.OnClickListener() //stop { @Override public void onclick(view arg0) { // TODO Auto-generated method stub _run = false; setroute(3); // 終 點 refreshmapview(); );
/* 取 得 GeoPoint 的 方 法 */ private GeoPoint getgeobylocation(location location) { GeoPoint gp = null; try { if (location!= null) { double geolatitude = location.getlatitude()*1e6; double geolongitude = location.getlongitude()*1e6; gp = new GeoPoint((int) geolatitude, (int) geolongitude); catch(exception e){ e.printstacktrace(); return gp;
/* 更 新 MapView 的 方 法 */ public void refreshmapview() { mapview.displayzoomcontrols(true); MapController mymc = mapview.getcontroller(); mymc.animateto(gp2); mymc.setzoom(18); mapview.setsatellite(false); // 不 用 衛 星 地 圖 mapview.setclickable(true); // 設 定 地 圖 可 以 被 選 取 移 動 /* 重 設 Overlay 的 方 法 */ private void resetoverlay() { List<Overlay> overlays = mapview.getoverlays(); overlays.clear();
/* 設 定 路 線 的 方 法 */ private void setroute(int mode) { MyOverLay moverlay = new MyOverLay(gp1,gp2,mode); List<Overlay> overlays = mapview.getoverlays(); overlays.add(moverlay);
修 改 LocationListener
修 改 LocationListener if(_run && iflocated){ gp2=getgeobylocation(location);; setroute(2); // 畫 線 refreshmapview(); gp1=gp2; else if(iflocated==false) { new AlertDialog.Builder(GPSLine.this).setTitle(" 定 位 ").setmessage(" 定 位 完 成, 可 以 開 始 使 用!").setPositiveButton(" 確 認 ",new DialogInterface.OnClickListener() { public void onclick(dialoginterface dialog, int which) { // TODO Auto-generated method stub ).show(); iflocated=true; MyDialog.dismiss();
補 充 沒 有 手 機 硬 體 時 怎 麼 測 試 一 些 硬 體 相 關 程 式?
Sensor Simulator http://code.google.com/p/openintents/wiki/sensorsimulator