android google map中使用mapView適應多個地圖標識 – Android移動開發技術文章_手機開發 Android移動開發教學課程

遇到一個需求,在地圖中標識多個地點(全國范圍),地點的gps放到一個xml文件中,以便隨時修改。要求是地圖要盡可能詳細,但是得把所有地點包括在內。
做法如下:
1、先得到數據的最大和最小經緯度,計算出數據的中心點(也是經緯度);
2、把地圖的zoom level默認一個比較大的值,如19或20之類的。這樣的話肯定是有很多地點是沒有顯示在mapView上的,然後再逐漸減少level的值,以顯示所有的地點。
    過程很清晰,看起來沒什麼問題,得出主要代碼如下:
Java代碼 
public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        comList = this.getComList();//獲取攝像頭數據 
        mapView = (MapView) findViewById(R.id.MapView01); 
        mapView.setStreetView(true); 
        mapView.setEnabled(true); 
        mapView.setClickable(true); 
        mapView.setBuiltInZoomControls(true); // 設置地圖支持縮放 
         
        System.out.println("長和寬:"+mapView.getHeight()+","+mapView.getWidth()); 
        mapController = (MapController)mapView.getController(); 
//      locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);// 位置管理器 
 
        // 設置地圖中心點 
        Double lat1 = (min_y + max_y) / 2 * 1E6; 
        Double lng1 = (min_x + max_x) / 2 * 1E6; 
        System.out.println("中心點:"+lat1+","+lng1); 
        GeoPoint geoPoint = new GeoPoint(lat1.intValue(), lng1.intValue()); 
        mapController.setCenter(geoPoint); 
        mapController.setZoom(16); 
         
        … 
 
        Drawable defaultMarker = getResources().getDrawable(R.drawable.arrow); 
        Drawable activeMarker = getResources().getDrawable(R.drawable.icon); 
        defaultMarker.setBounds(0, 0, defaultMarker.getMinimumWidth(), 
                defaultMarker.getMinimumHeight()); 
        PositionsOverlay posOverlay = new PositionsOverlay(defaultMarker, 
                comList, activeMarker,this); 
        List<Overlay> overlays = getMapView().getOverlays(); 
        overlays.add(posOverlay); 
         
         
        //根據左上角來判斷 
        Projection proj = mapView.getProjection(); 
        MapController mapController = mapView.getController(); 
        GeoPoint geoFromPix = proj.fromPixels(0, 0);//  
        double pix_lng = geoFromPix.getLongitudeE6() / 1E6;// 左上角屏幕像素轉換成的gps經度 
        double pix_lat = geoFromPix.getLatitudeE6() / 1E6;// 左上角屏幕像素轉換成的gps緯度 
 
        // System.out.println("縮放前中心點: "+mapView.getMapCenter()); 
        while (min_x < pix_lng) {// 數據中最小經度如果小於屏幕所對應的最小經度(出界),則縮小地圖,讓數據顯示到屏幕中 
            System.out.println("縮小地圖1:" + min_x + "," + pix_lng); 
            mapController.setZoom(mapView.getZoomLevel() – 1); 
            pix_lng = mapView.getProjection().fromPixels(0, 0) 
                    .getLongitudeE6() / 1E6; 
            pix_lat = mapView.getProjection().fromPixels(0, 0) 
                    .getLatitudeE6() / 1E6; 
 
        } 
        while (max_y > pix_lat) {// 數據中最大緯度如果大於屏幕所對應的最小緯度(出界),則縮小地圖,讓數據顯示到屏幕中 
            System.out.println("縮小地圖2"); 
            mapController.setZoom(mapView.getZoomLevel() – 1); 
            pix_lat = mapView.getProjection().fromPixels(0, 0) 
                    .getLatitudeE6() / 1E6; 
        } 


運行結果,後臺狂刷:
Java代碼 
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444 
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444 
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444 
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444 
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444 
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444 


將左上角換成右下角,發現取不到mapView的寬和高。。。
上網找瞭下,說法如下:
Java代碼 
A common mistake made by new Android developers is to use 
the width and height of a view inside its constructor. When 
a view’s constructor is called, Android doesn’t know yet how 
big the view will be, so the sizes are set to zero. The real sizes 
are calculated during the layout stage, which occurs after 
construction but before anything is drawn. You can use the 
onSizeChanged( )method to be notified of the values when they 
are known, or you can use the getWidth( ) and getHeight( )methods 
later, such as in the onDraw( ) method 

http://www.coderanch.com/t/435390/Android/Mobile/screen-size-at-run-time
要等開始佈局時才能得到寬和高等特性?這麼說的話使用
Java代碼 
pix_lng = mapView.getProjection().fromPixels(0, 0) 
                    .getLongitudeE6() / 1E6; 

也是沒意義的瞭。。。
這樣的話隻能等mapView渲染完畢才能處理瞭.
本來想使用mapView的draw方法來處理,但是無從下手(繼承mapView類來重寫draw方法?),隻好寫瞭個線程,監聽mapView是否完成(完成的話height和width都不會等0瞭),然後把剛才那段代碼放到線程裡,成功瞭。。。
新線程代碼:

Java代碼 
public void run() { 
        while (mapView.getHeight() == 0) { 
            System.out.println("mapView等於0,mapView還沒渲染完畢"); 
            try { 
                Thread.currentThread().sleep(100); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
        if (mapView.getHeight() != 0) { 
            /*
             * 使用setZoom來讓數據標簽自適應屏幕
             */ 
 
            //根據左上角來判斷 
            Projection proj = mapView.getProjection(); 
            MapController mapController = mapView.getController(); 
            GeoPoint geoFromPix = proj.fromPixels(0, 0);//  
            double pix_lng = geoFromPix.getLongitudeE6() / 1E6;// 左上角屏幕像素轉換成的gps經度 
            double pix_lat = geoFromPix.getLatitudeE6() / 1E6;// 左上角屏幕像素轉換成的gps緯度 
 
            // System.out.println("縮放前中心點: "+mapView.getMapCenter()); 
            while (min_x < pix_lng) {// 數據中最小經度如果小於屏幕所對應的最小經度(出界),則縮小地圖,讓數據顯示到屏幕中 
                System.out.println("縮小地圖1:" + min_x + "," + pix_lng); 
                mapController.setZoom(mapView.getZoomLevel() – 1); 
                pix_lng = mapView.getProjection().fromPixels(0, 0) 
                        .getLongitudeE6() / 1E6; 
                pix_lat = mapView.getProjection().fromPixels(0, 0) 
                        .getLatitudeE6() / 1E6; 
 
            } 
            while (max_y > pix_lat) {// 數據中最大緯度如果大於屏幕所對應的最小緯度(出界),則縮小地圖,讓數據顯示到屏幕中 
                System.out.println("縮小地圖2"); 
                mapController.setZoom(mapView.getZoomLevel() – 1); 
                pix_lat = mapView.getProjection().fromPixels(0, 0) 
                        .getLatitudeE6() / 1E6; 
            } 
            System.out.println("mapView的值:" + mapView.getHeight()); 
        } 
    } 

剛才那段代碼改成:
Java代碼 
public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        comList = this.getComList();//獲取攝像頭數據 
        mapView = (MapView) findViewById(R.id.MapView01); 
        mapView.setStreetView(true); 
        mapView.setEnabled(true); 
        mapView.setClickable(true); 
        mapView.setBuiltInZoomControls(true); // 設置地圖支持縮放 
         
        System.out.println("長和寬:"+mapView.getHeight()+","+mapView.getWidth()); 
        mapController = (MapController)mapView.getController(); 
//      locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);// 位置管理器 
 
        // 設置地圖中心點 
        Double lat1 = (min_y + max_y) / 2 * 1E6; 
        Double lng1 = (min_x + max_x) / 2 * 1E6; 
        System.out.println("中心點:"+lat1+","+lng1); 
        GeoPoint geoPoint = new GeoPoint(lat1.intValue(), lng1.intValue()); 
        mapController.setCenter(geoPoint); 
        mapController.setZoom(16); 
         
        … 
 
        Drawable defaultMarker = getResources().getDrawable(R.drawable.arrow); 
        Drawable activeMarker = getResources().getDrawable(R.drawable.icon); 
        defaultMarker.setBounds(0, 0, defaultMarker.getMinimumWidth(), 
                defaultMarker.getMinimumHeight()); 
        PositionsOverlay posOverlay = new PositionsOverlay(defaultMarker, 
                comList, activeMarker,this); 
        List<Overlay> overlays = getMapView().getOverlays(); 
        overlays.add(posOverlay); 
         
         
        //啟動新的線程來監視mapView是否渲染完畢,渲染完畢則開始調整mapView的縮放水平以適合全部數據 
        SelfAdaptionMapView cv = new SelfAdaptionMapView(mapView,max_x,min_y,min_x,max_y); 
        new Thread(cv).start(); 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。