1

从位图创建地图标记的正确方法是什么?

我正在使用 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我不会遇到同样的问题。

4

1 回答 1

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);
    }
}

当然,如果您的不同标记数量有限,这很有效。只需在您的活动开始时创建工厂,并在停止时将其销毁,您将只有两个位图在内存中,并避免加载/释放大量位图。

于 2013-02-24T09:24:43.967 回答