2013-02-24 3 views
1

비트 맵에서지도 마커를 만드는 올바른 방법은 무엇입니까?비트 맵에서 만든 안드로이드지도 마커를 만들고 사용하는 올바른 방법은 무엇입니까?

Google지도 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 장치에 5킬로바이트 크기 여러 가지 빛깔의 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 개의 다른 아이콘이 있습니다. 그리고 더 많은 시간이있을 것입니다. 현재 보이는지도 투영에 따라 동적 마커로드를 사용합니다. 그래서 메모리에 캐시 된 마커 비트 맵을 유지하는 것이 좋은 방법이라는 것을 알지 못합니다. 그 중 일부는 한 번 보여 질 수도 있고 다시는 볼 수도 없을 수도 있습니다. –

+0

음, 50 개의 마커를 캐싱하는 것이 200 배의로드보다 낫다고 생각합니다. Bitmap 가비지 수집이 안드로이드에서 얼마나 이상한지 생각해 보라. –

+0

그러나 메모리에 20 개의 "원본"비트 맵을 캐시하면 각 마커에 대한 비트 맵 복사본을 만들어야합니다. 그런 다음 캐시 된 비트 맵은 일종의 중복 코드입니까? 아니면 메모리에로드하여 복사본을 만드는 것이 더 낫습니까? –

관련 문제