2013-02-24 17 views
1

什麼是從位圖創建地圖標記的正確方法?正確創建和使用從位圖創建的Android地圖標記的方法?

我正在使用Google Maps Android v1並現在移至v2。
我的地圖包含多個從位圖創建的標記。
每個標記由位圖圖像和其上的一些文本組成,每個標記可能不同。所以我必須修改內存中的每個位圖。
我加載標記相似圖片:

private Bitmap getMarker(final String name) { 
    Bitmap result = BitmapFactory.decodeFile(context.getFilesDir() + "/markers/" + name + ".png"); 

    if (result == null) { 
     // must make a mutable copy as by default resource is returned immutable 
     result = decodeResource(context.getResources(), R.drawable.default_marker).copy(Config.ARGB_8888, true); 
    } else { 
     result = result.copy(Config.ARGB_8888, true); 
    } 

    return result; 
} 

,然後將其應用自定義文本用帆布:

private void applyText(Bitmap marker, Paint paint, String text) { 
    Canvas canvas = new Canvas(marker); 
    canvas.drawText(text, calculateTextX(marker, paint, text), calculateTextY(marker, paint, text), paint); 
} 

標記圖像〜在MDPI設備5KB大小多色PNG文件。

隨着Google Maps Android v1時不時在某些設備上(難以重現)我得到java.lang.OutOfMemoryError解碼時的位圖圖像。我有一種感覺,我做錯了什麼... 我想肯定知道與Google Maps Android v2我不會得到同樣的問題。

回答

2

我幾天前切換到v2時遇到了同樣的問題。 我認爲最重要的是儘可能少地將圖像加載到內存中,因此只要您需要,可以將標記原始位圖保留在內存中。

這裏的代碼顯示我是如何做的一個樣本:

public class MyMarkerFactoryFactory { 

    private Context ctx; 
    private Bitmap cachedMarkerBase; // Cached bitmap 
    private Bitmap currentMarker; // Working copy 
    private final List<Marker> markers = new ArrayList<Marker>(); 

    public MyMarkerFactoryFactory(Context ctx, String markerName, int markerWidth, int markerHeight) { 
     this.ctx = ctx; 

     Bitmap src = BitmapFactory.decodeFile(ctx.getFilesDir() + "/markers/" + markerName + ".png"); 
     int srcBitmapWidth = src.getWidth(); 
     int srcBitmapHeight = src.getHeight(); 
     if (markerWidth != srcBitmapWidth && markerHeight != srcBitmapHeight) { 
      // The rendering bitmap will depend on provided width and height 
      // In my case it's because the bitmap does not have the same pixel size 
      // depending on the display pixel density. So I've declared the size I 
      // I want in "dp" somewhere else and fetch it from ctx.getDimen 
      // createScaledBitmap will return the same bitmap if you are scaling 
      // to the same size, so it's good to test the size before you rescale 
      // otherwise you are likely to recycle() the bitmap you wanted to use. 
      cachedMarkerBase = Bitmap.createScaledBitmap(src, markerWidth, markerHeight, false); 
      src.recycle(); 
     } else { 
      cachedMarkerBase = src; 
     } 
     currentMarker = cachedMarkerBase.copy(cachedMarkerBase.getConfig(), true); 
    } 

    public void onDestroy() { 
     clearOverlays(); 
     if (cachedMarkerBase != null) { 
      cachedMarkerBase.recycle(); 
      cachedMarkerBase = null; 
     } 
     if (currentMarker != null) { 
      currentMarker.recycle(); 
      currentMarker = null; 
     } 
    } 

    public void clearOverlays() { 
     for (Marker marker : markers) { 
      marker.remove(); 
     } 
     markers.clear(); 
    } 

    public void addOverlay(GoogleMap map, LatLng position, String myText) { 
     drawMarkerWith(myText); 
     BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(currentMarker); 
     markers.add(map.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).icon(bitmapDescriptor).position(position))); 
    } 

    private void drawMarkerWith(String myText) { 
     // Copy image from cache 
     for (int i = 0; i < cachedMarkerBase.getWidth(); i++) { 
      for (int j = 0; j < cachedMarkerBase.getHeight(); j++) { 
       currentMarker.setPixel(i, j, cachedMarkerBase.getPixel(i, j)); 
      } 
     } 
     int x = currentMarker.getWidth()/2, y = currentMarker.getHeight()/2; 

     Paint paintForText = new Paint() 
     paintForText.setTextSize(7f); // TODO 

     // Draw text 
     Canvas canvas = new Canvas(currentMarker); 
     int x = 0; // TODO 
     int y = 0; // TODO 
     canvas.drawText(myText, x, y, paintForText); 
    } 
} 

這種運作良好,當然,如果你有不同的標記的數量有限。只需在活動開始時創建工廠,並在停止時將其銷燬,並且內存中只有兩個位圖,並避免加載/釋放大量位圖。

+0

目前我有20個不同的標記。而且會有更多的時間。我使用動態標記加載取決於當前可見的地圖投影。所以我不知道在內存中保存標記位圖是否是一件好事,因爲它們中的一些可能會顯示一次,從未再見過...... – 2013-02-24 10:05:41

+0

嗯,我認爲緩存50個標記比加載200次要好考慮Android中奇怪的位圖垃圾收集是如何發生的。 – 2013-02-24 10:07:43

+0

但是如果我在內存中緩存20個「原始」位圖,那麼我仍然需要爲每個標記創建一個位圖的副本,那麼這些緩存的位圖有點多餘?還是將它裝入內存並複製它會更好? – 2013-02-24 10:59:46