Google Map程式範例
此程式為動態下載Google Map的程式範例,能隨者使用者(GPS)移動所在位址上網下載Google Map的地圖再用麥卡托投影法轉換後顯示在螢幕畫面上。
圖2-4
以下為動態的Google Map程式碼:
專案下載:DynamicLoadGoogleMap.rar
主程式: DynamicLoadGoogleMap.java
package DynamicLoadGoogleMap.a; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.Window; import android.view.WindowManager; public class DynamicLoadGoogleMap extends Activity { // 主迴圈執行緒 public Thread loopThread; // 畫布 private Surface surface; // GPS初始化 private LocationManager localManager; private LocationListener locationListener; // 暫存圖片 private Bitmap tempMap; // 地圖圖片 private Bitmap[] mapBitmap; // 地圖物件 private Map[] mapObj; // 觸控偏移位置 private int offsetX, offsetY; // 顯示GPS經緯度 private Text lngText; private Text latText; // 上一次的觸控位置 private int mouseDownX; private int mouseDownY; // 迴圈變數 private int f; // 程式進入點 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 無標題列 requestWindowFeature(Window.FEATURE_NO_TITLE); // 全螢幕設定 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 初始化GPS服務 localManager = (LocationManager) getSystemService(Activity.LOCATION_SERVICE); // 初始化事件 locationListener = new MyLocationListener(); // 事件更新 localManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); // 取得螢幕大小 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); GV.scaleWidth = dm.widthPixels; GV.scaleHeight = dm.heightPixels; GV.halfWidth = GV.scaleWidth >> 1; GV.halfHeight = GV.scaleHeight >> 1; loopThread = new Thread(new Loop()); loopThread.setDaemon(true); surface = new Surface(this); setContentView(surface); } // 暫停程式 @Override protected void onPause() { // 清除GPS更新事件 localManager.removeUpdates(locationListener); if (loopThread != null) loopThread.interrupt(); super.onPause(); } // 觸控事件 @Override public boolean onTouchEvent(MotionEvent event) { int x = (int)event.getX(); int y = (int)event.getY(); switch(event.getAction()) { case MotionEvent.ACTION_DOWN: mouseDownX = x; mouseDownY = y; break; case MotionEvent.ACTION_MOVE: int movX = x - mouseDownX; int movY = y - mouseDownY; if (Math.abs(movX - mouseDownX) > 5) { offsetX = movX; } if (Math.abs(movY - mouseDownY) > 5) { offsetY = movY; } break; } return super.onTouchEvent(event); } // 初始化 private void Initialize() { // GV.setLng(118.32198666666666); // GV.setLat(24.449396666666669); lngText = new Text("", 20, 20, Color.YELLOW); latText = new Text("", 20, 40, Color.YELLOW); // 初始化地圖 mapBitmap = new Bitmap[4]; // 初始化地圖 mapObj = new Map[mapBitmap.length]; int x,y; // 設定地圖的起始位置 for (f = 0;f <mapObj.length;f++) { x = -GV.halfWidth + GV.scaleWidth * (f % 2); y = -GV.halfHeight + GV.scaleHeight * (f / 2); mapObj[f] = new Map(x, y, GV.lngX + x, GV.latY + y); StartLoadMap(f, mapObj[f].lng, mapObj[f].lat); } } // 更新經緯度 private void updateLngLat() { // 如果有異動則 if (offsetX != 0) { // 更新經緯度 GV.addLngX(-offsetX); offsetX = 0; } // 如果有異動則 if (offsetY != 0) { // 更新經緯度 GV.addLatY(-offsetY); offsetY = 0; } } // 更新動作 private void Update() { // 更新經緯度 updateLngLat(); // 取得經緯度的異動位移 int x = GV.oldLngX - GV.lngX; int y = GV.oldLatY - GV.latY; // 如果經緯度更新 if (x != 0 || y != 0) { if (GV.oldLngX != 0 && GV.oldLatY != 0) { // 移動地圖 MoveMap(x, y); }else Initialize(); // 儲存這次的經緯度絕對點 GV.oldLngX = GV.lngX; GV.oldLatY = GV.latY; } lngText.message = "經度:" + GV.lng; latText.message = "緯度:" + GV.lat; } // 移動地圖 private void MoveMap(int X,int y) { for (f = 0; f < mapObj.length; f++) { mapObj[f].x += X; // 超出範圍重設位置 if (mapObj[f].x < -GV.scaleWidth) { mapObj[f].x += (GV.scaleWidth << 1); mapObj[f].addLngX(GV.scaleWidth << 1); // 從網路載入地圖 StartLoadMap(f, mapObj[f].lng, mapObj[f].lat); } else if (mapObj[f].x > GV.scaleWidth) { mapObj[f].x -= (GV.scaleWidth << 1); mapObj[f].addLngX(-(GV.scaleWidth << 1)); // 從網路載入地圖 StartLoadMap(f, mapObj[f].lng, mapObj[f].lat); } } for (f = 0; f < mapObj.length; f++) { mapObj[f].y += y; // 超出範圍重設位置 if (mapObj[f].y < -GV.scaleHeight) { mapObj[f].y += (GV.scaleHeight << 1); mapObj[f].addLatY(GV.scaleHeight << 1); // 從網路載入地圖 StartLoadMap(f, mapObj[f].lng, mapObj[f].lat); } else if (mapObj[f].y > GV.scaleHeight) { mapObj[f].y -= (GV.scaleHeight << 1); mapObj[f].addLatY(-(GV.scaleHeight << 1)); // 從網路載入地圖 StartLoadMap(f, mapObj[f].lng, mapObj[f].lat); } } } // 以執行緒載入地圖 private void StartLoadMap(int index, double lng, double lat) { mapBitmap[index] = null; Thread loadMapThread = new Thread(new LoadMapFromNet(index, lng, lat)); loadMapThread.setDaemon(true); loadMapThread.start(); } // 從網路載入地圖 class LoadMapFromNet implements Runnable { private int index; private double lng; private double lat; public LoadMapFromNet(int index,double lng,double lat) { this.index = index; this.lng = lng; this.lat = lat; } public void run() { tempMap = GetGoogleMap.getMap(lng, lat, GV.scaleWidth, GV.scaleHeight); if (tempMap != null) mapBitmap[index] = tempMap; } } // 更新畫面 private void Draw() { // 鎖定canvas Canvas canvas = surface.mHolder.lockCanvas(null); if (canvas != null) { // 清除畫面 canvas.drawColor(Color.BLACK); // 畫出地圖 for (f = 0; f < mapBitmap.length; f++) { if (mapBitmap[f] != null) canvas.drawBitmap(mapBitmap[f], mapObj[f].x, mapObj[f].y, null); } // 畫出lng canvas.drawText(lngText.message, lngText.x, lngText.y, lngText.paint); // 畫出lat canvas.drawText(latText.message, latText.x, latText.y, latText.paint); // 解除鎖定 surface.mHolder.unlockCanvasAndPost(canvas); } } // 主迴圈 public class Loop implements Runnable { public void run() { Initialize(); while(!Thread.interrupted()) { Update(); Draw(); try { Thread.sleep(33); } catch (InterruptedException e) { e.printStackTrace(); } } } } // GPS監聽者 class MyLocationListener implements LocationListener { // GPS位置事件更新 public void onLocationChanged(Location loc) { if (loc != null){ // 取得經緯度 GV.setLng(loc.getLongitude()); GV.setLat(loc.getLatitude()); } } public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } } }
程式: GetGoogleMap.java
22行的URL url = new URL(urlString);為直接連接網路時使用、24行的URL url = new URL("http","proxy0.internal",3128, urlString);為使用代理伺服器時使用。
package DynamicLoadGoogleMap.a; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.net.URL; import java.net.URLConnection; public class GetGoogleMap { // 取得GoogleMap public static Bitmap getMap(double Longitude,double Latitude,int width,int height) { try { String key = "ABQIAAAAz2rjkrilGZTguphQT5RQqxQnA14KtgqpIfJzkpdB1-oq1QYeLRTl0Szkt5Yli5Jv9oBOrf85JNpgIw"; // String key = "ABQIAAAAz2rjkrilGZTguphQT5RQqxQQIe5j7nozdTIq37ll2BjQmE8XsxTUxidRqBWWrDXy2cwQU686YRJCTQ"; int zoom = 19; String size = String.format("%1sx%2s", width, height); // 網址 String urlString = String.format("http://maps.google.com/staticmap?center=%1$s,%2$s&zoom=%3$s&size=%4$s&maptype=hybrid&sensor=false&key=%5$s", Latitude, Longitude, zoom, size,key); // URL url = new URL(urlString); // use proxy server URL url = new URL("http","proxy0.internal",3128, urlString); // 連線 URLConnection conn = url.openConnection(); conn.connect(); // 取得圖片串流 Bitmap tempBitmap = BitmapFactory.decodeStream(conn.getInputStream()); if (tempBitmap != null) return tempBitmap; else return null; } catch (Exception ex) { return null; } } }
程式: GV.java
package DynamicLoadGoogleMap.a; // 共用變數 public class GV { // 經度 public static double lng = 0.0; // 緯度 public static double lat = 0.0; // 經度絕對點 public static int lngX = 0; // 緯度絕對點 public static int latY = 0; // 上一次的經緯度絕對點 public static int oldLngX = 0; public static int oldLatY = 0; // 螢幕長寬 public static int scaleWidth = 0; public static int scaleHeight = 0; public static int halfWidth = 0; public static int halfHeight = 0; // 地圖縮放係數 public static int zoom = 19; public static void setLng(double x) { oldLngX = lngX; lng = x; lngX = LngToX(x); } public static void setLat(double y) { oldLatY = latY; lat = y; latY = LatToY(y); } public static void addLngX(int x) { setLngX(lngX + x); } public static void addLatY(int y) { setLatY(latY + y); } public static void setLngX(int x) { oldLngX = lngX; lngX = x; lng = XToLng(lngX); } public static void setLatY(int y) { oldLatY = latY; latY = y; lat = YToLat(latY); } // 經度轉成點(point) public static int LngToX(double Longitude) { int numberOfTiles = 1 << zoom << 8; return (int)((Longitude + 180.0) * numberOfTiles / 360.0); } // 緯度轉成點(point) public static int LatToY(double Latitude) { int numberOfTiles = 1 << zoom << 8; double projection = Math.log(Math.tan(Math.PI / 4 + ((Latitude / 180 * Math.PI) / 2))); double y = (projection / Math.PI); y = 1.0 - y; y = y / 2.0 * numberOfTiles; return (int)y; } // 點(X)轉成經度 public static double XToLng(int pointX) { int numberOfTiles = 1 << zoom << 8; return (pointX * (360.0 / numberOfTiles)) - 180.0; } // 點(Y)轉成緯度 public static double YToLat(int pointY) { int numberOfTiles = 1 << zoom << 8; double Latitude = pointY * (2.0 / numberOfTiles); Latitude = 1 - Latitude; Latitude = Latitude * Math.PI; Latitude = Math.atan(Math.sinh(Latitude)) * 180.0 / Math.PI; return Latitude; } }
程式: Map.java
package DynamicLoadGoogleMap.a; public class Map { // 繪圖位置 public int x; public int y; // 中心點經緯度 public double lng; public double lat; // 中心點絕對點 public int lngX; public int latY; public Map(int x, int y, int lngX, int latY) { this.x = x; this.y = y; setLngX(lngX); setLatY(latY); } public void addLngX(int x) { setLngX(lngX + x); } public void addLatY(int y) { setLatY(latY + y); } public void setLngX(int x) { lngX = x; lng = GV.XToLng(lngX); } public void setLatY(int y) { latY = y; lat = GV.YToLat(latY); } }
程式: Surface.java
package DynamicLoadGoogleMap.a; import android.view.SurfaceHolder; import android.view.SurfaceView; public class Surface extends SurfaceView implements SurfaceHolder.Callback{ public SurfaceHolder mHolder; private DynamicLoadGoogleMap context; public Surface(DynamicLoadGoogleMap context) { super(context); this.context = context; mHolder = getHolder(); mHolder.addCallback(this); } public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub } public void surfaceCreated(SurfaceHolder arg0) { context.loopThread.start(); } public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub } }
程式: Text.java
package DynamicLoadGoogleMap.a; import android.graphics.Paint; import android.graphics.Typeface; public class Text { public int x; public int y; public Paint paint; public String message; public Text(String message, int x, int y, int color) { this.message = message; this.x = x; this.y = y; paint = new Paint(); paint.setTextSize(12); paint.setColor(color); paint.setTypeface(Typeface.MONOSPACE); } }
AndroidManifest.xml為使用權限:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="DynamicLoadGoogleMap.a" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> <activity android:name=".DynamicLoadGoogleMap" 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-sdk android:minSdkVersion="4" /> <!-- GPS權限設定 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 網路權限 --> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
程式影片解說
page revision: 12, last edited: 15 Dec 2010 06:04
Post preview:
Close preview