谷歌地图标记在缩放时被边界矩形取代

13

我正在Fragment中使用SupportMapFragment,并使用最近的Android Map Utils进行聚类。在Google Play服务更新到9.0.83后,谷歌单个地图标记被缩放时替换为边界矩形。只有单个标记被替换,聚类标记正常。更改应用程序清单中的硬件加速参数不会改变任何内容。如何解决?

enter image description here

P.S.

compile 'com.google.android.gms:play-services-maps:8.4.0'

2
似乎有人关于这个问题提交了一个错误报告 https://github.com/googlemaps/android-maps-utils/issues/276 - tyczj
3个回答

7
我使用了@bishop87的简化版解决方法,具体请参考github项目上的问题。我还为集群位图添加了缓存,这使得它更加安全,避免了OOM(内存不足)的问题。
如果您没有集群渲染器,请使用此代码或将其移至自己的代码中: SimpleClusterRenderer.java
public class SimpleClusterRenderer extends DefaultClusterRenderer<AuctionItem> {
    private static final int CLUSTER_PADDING = 12;
    private static final int ITEM_PADDING = 7;

    private final Bitmap mIconItemGreen;
    private final IconGenerator mIconClusterGenerator;
    private final float mDensity;

    public SimpleClusterRenderer(Context context, GoogleMap map, ClusterManager<AuctionItem> clusterManager) {
        super(context, map, clusterManager);

        mDensity = context.getResources().getDisplayMetrics().density;

        mIconClusterGenerator = new CachedIconGenerator(context);
        mIconClusterGenerator.setContentView(makeSquareTextView(context, CLUSTER_PADDING));
        mIconClusterGenerator.setTextAppearance(com.google.maps.android.R.style.ClusterIcon_TextAppearance);

        IconGenerator iconItemGenerator = new IconGenerator(context);
        iconItemGenerator.setContentView(makeSquareTextView(context, ITEM_PADDING));
        iconItemGenerator.setBackground(makeClusterBackground(ContextCompat.getColor(context, R.color.simple_green)));
        mIconItemGreen = iconItemGenerator.makeIcon();
    }

    @Override
    protected void onBeforeClusterItemRendered(AuctionItem item, MarkerOptions markerOptions) {
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(mIconItemGreen));
    }

    @Override
    protected void onBeforeClusterRendered(Cluster<AuctionItem> cluster, MarkerOptions markerOptions) {
        int clusterSize = getBucket(cluster);

        mIconClusterGenerator.setBackground(makeClusterBackground(getColor(clusterSize)));
        BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(mIconClusterGenerator.makeIcon(getClusterText(clusterSize)));
        markerOptions.icon(descriptor);
    }

    @Override
    protected boolean shouldRenderAsCluster(Cluster<AuctionItem> cluster) {
        // Always render clusters.
        return cluster.getSize() > 1;
    }

    private int getColor(int clusterSize) {
        float size = Math.min((float) clusterSize, 300.0F);
        float hue = (300.0F - size) * (300.0F - size) / 90000.0F * 220.0F;
        return Color.HSVToColor(new float[]{hue, 1.0F, 0.6F});
    }

    private LayerDrawable makeClusterBackground(int color) {
        ShapeDrawable mColoredCircleBackground = new ShapeDrawable(new OvalShape());
        mColoredCircleBackground.getPaint().setColor(color);
        ShapeDrawable outline = new ShapeDrawable(new OvalShape());
        outline.getPaint().setColor(0x80ffffff);
        LayerDrawable background = new LayerDrawable(new Drawable[]{outline, mColoredCircleBackground});
        int strokeWidth = (int) (mDensity * 3.0F);
        background.setLayerInset(1, strokeWidth, strokeWidth, strokeWidth, strokeWidth);
        return background;
    }

    private SquareTextView makeSquareTextView(Context context, int padding) {
        SquareTextView squareTextView = new SquareTextView(context);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        squareTextView.setLayoutParams(layoutParams);
        squareTextView.setId(R.id.text);
        int paddingDpi = (int) (padding * mDensity);
        squareTextView.setPadding(paddingDpi, paddingDpi, paddingDpi, paddingDpi);
        return squareTextView;
    }
}

CachedIconGenerator.java

public class CachedIconGenerator extends IconGenerator {

    private final LruCache<String, Bitmap> mBitmapsCache;
    private String mText;

    public CachedIconGenerator(Context context) {
        super(context);

        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;
        mBitmapsCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // The cache size will be measured in kilobytes rather than
                // number of items.
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    public Bitmap makeIcon(String text) {
        mText = text;
        return super.makeIcon(text);
    }

    @Override
    public Bitmap makeIcon() {
        if (TextUtils.isEmpty(mText)) {
            return super.makeIcon();
        } else {
            Bitmap bitmap = mBitmapsCache.get(mText);
            if (bitmap == null) {
                bitmap = super.makeIcon();
                mBitmapsCache.put(mText, bitmap);
            }
            return bitmap;
        }
    }
}

附注:您还需要将 R.color.simple_green 替换为您想要的标记颜色。

另外,忘了提到,这种方法几乎不会影响性能。因此,如果谷歌在下一个Play服务应用程序版本中修复了此问题,则最好使用不同的方法更新此解决方案以适应Play Services 9.0.83和其他版本。


1
为每个项目创建自己的BitmapDescriptor可能会在某些设备上导致OutOfMemoryException或类似问题。据我所知,这是因为聚类库在重新计算聚类版本之前显示所有点。 - tse
是的,解决方案可行 - 但会产生很多OutOfMemoryException异常。 - Sinisa Kendel
@Alexandr,你承诺要讲述更好的解决方法,避免内存不足异常。 - tse
使用这个解决方法,我遇到了 java.lang.RuntimeException: Could not copy bitmap to parcel blob 错误,这是由 BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(mIconClusterGenerator.makeIcon(getClusterText(clusterSize)));onBeforeClusterRendered 中触发的。 - Dellkan
@Dellkan,这很奇怪。但我不知道为什么会发生这种情况。如果您有解决方案,请编辑我的答案。 - Oleksandr
显示剩余2条评论

5
根据tyczj的说法,这个问题是由于Google Play服务(专有二进制文件)升级到9.0.x时开始出现的。从Github问题讨论的情况来看,解决方法如下:
可能可以从gmaps-api-issues页面中找到解决方法: 将marker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.drawableid))更改为marker.setIcon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.drawableid)));//可能会影响一般内存消耗,尽管我还没有测试过比应用程序报告的更多的问题。
此外,注意到: 我可以证实这个问题。除了@Mavamaarten之外,您不能重复使用标记图像。
(来源:https://github.com/googlemaps/android-maps-utils/issues/276

最后一部分是什么意思?“您不得重复使用标记图像”? - user5156016
1
基本上,解决方法是您始终加载新的位图实例...而不是共享相同的实例。 - Ray W
我正在分享同一个,但我没有遇到这个错误。这正常吗? - user5156016
@RayW 但是你可以重复使用位图,只需将位图描述符更改为LRUCache中的位图即可。 - Spurdow

0
对我来说,问题发生在以下情况下:(1)我删除一个带有自定义图标的标记或(2)在创建后设置新图标...
为解决第一种情况,您需要在删除之前设置默认图标...
if (marker != null) {
    marker.setIcon(BitmapDescriptorFactory.defaultMarker());
    marker.remove();
}

为了解决第二种情况,您需要添加一个带有新自定义图标的标记副本,并在同一第一种情况中稍后删除...
在 Google 地图团队修复此问题之前,这是一个解决方案...
祝好运...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接