google maps api v2内存不足错误

Sal*_*van 17 android bitmap out-of-memory markerclusterer google-maps-android-api-2

我的应用程序中存在巨大的内存问题.我正在使用谷歌地图api v2 ClusterManager和自定义标记.我markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));根据其类别通过调用为每个标记提供图像.问题是:在几次屏幕旋转后,我的应用程序因OOM错误而崩溃:

05-14 11:04:12.692  14020-30201/rokask.rideabike E/art? Throwing OutOfMemoryError "Failed to allocate a 4194316 byte allocation with 1627608 free bytes and 1589KB until OOM"
05-14 11:04:12.722  14020-30201/rokask.rideabike E/AndroidRuntime? FATAL EXCEPTION: GLThread 19179
Process: rokask.rideabike, PID: 14020
java.lang.OutOfMemoryError: Failed to allocate a 4194316 byte allocation with 1627608 free bytes and 1589KB until OOM
        at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
        at android.graphics.Bitmap.nativeCreate(Native Method)
        at android.graphics.Bitmap.createBitmap(Bitmap.java:939)
        at android.graphics.Bitmap.createBitmap(Bitmap.java:912)
        at android.graphics.Bitmap.createBitmap(Bitmap.java:879)
        at com.google.maps.api.android.lib6.gmm6.n.c.i.a(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.c.l.a(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.c.l.a(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.c.l.b(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.c.b.ak.a(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.c.b.as.a(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.x.a(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.l.a(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.l.b(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.cv.f(Unknown Source)
        at com.google.maps.api.android.lib6.gmm6.n.cv.run(Unknown Source)
Run Code Online (Sandbox Code Playgroud)

我有一个LruCache与我Bitmap的对象,这意味着我不重新创建它们,而是重用它们.我可以清楚地看到每个Bitmap对象都是从缓存中获取的,而不是从其他地方获取的.但是,如果Bitmap它还没有在缓存中(第一次加载),我会从我的应用程序的内部存储中加载它,但只有Bitmap在第一次加盖时它才会开心.我保留了LruCache一个保留Fragment实例的实例,并在DefaultClusterRenderer<MyObject>每次Activity重新创建时将其传递给我的自定义对象,并且需要重新绘制地图.

这是我的DefaultClusterRenderer<MyItem>扩展:

public class DotRenderer extends DefaultClusterRenderer<Dot> {
private final String internalStorageDir;
private final LruCache<String, Bitmap> lruCache;

public DotRenderer(Context context, GoogleMap googleMap, ClusterManager<Dot> clusterManager,
                   LruCache<String, Bitmap> lruCache, String internalStorageDir)
{
    super(context, googleMap, clusterManager);
    //this.bitmaps = bitmaps;
    this.internalStorageDir = internalStorageDir;
    this.lruCache = lruCache;
}

@Override
protected void onBeforeClusterItemRendered(Dot mapObject, MarkerOptions markerOptions) {
    markerOptions.title(mapObject.getTitle());
    String id = Integer.toString(mapObject.getTypeId());
    //
    Bitmap bitmap = getBitmapFromMemCache(id);
    if (bitmap == null) {
        Log.d(MainActivity.LOG_TAG, "reading bitmap from storage.");
        Map.Entry<String, Bitmap> bitmapEntry
                = BitmapManager.getBitmapFromStorage(internalStorageDir, id);
        if (bitmapEntry != null) {
            markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmapEntry.getValue()));
            addBitmapToMemCache(id, bitmapEntry.getValue());
        }
    } else {
        Log.d(MainActivity.LOG_TAG, "reading bitmap from cache.");
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));
    }
}

private void addBitmapToMemCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        lruCache.put(key, bitmap);
    }
}

private Bitmap getBitmapFromMemCache(String key) {
    return lruCache.get(key);
}
}
Run Code Online (Sandbox Code Playgroud)

这是Activity我开始加载地图的代码(每次屏幕方向更改时都会执行此代码):

    ClusterManager<Dot> clusterManager = new ClusterManager<>(this, googleMap);
    clusterManager.setOnClusterItemInfoWindowClickListener(
            new ClusterManager.OnClusterItemInfoWindowClickListener<Dot>() {
                @Override
                public void onClusterItemInfoWindowClick(Dot dot) {
                    int id = dot.getId();
                    String title = dot.getTitle();
                    Log.d(LOG_TAG, "clicked marker with id " + id
                            + " and title " + title + ".");
                    Intent infoWindowActivityIntent =
                            new Intent(MainActivity.this, InfoWindowActivity.class);
                    infoWindowActivityIntent.putExtra("dotId", id);
                    infoWindowActivityIntent.putExtra("dotTitle", title);
                    startActivity(infoWindowActivityIntent);
                }
            });
    googleMap.setOnCameraChangeListener(clusterManager);
    googleMap.setOnInfoWindowClickListener(clusterManager);

    DotRenderer dotRenderer =
            new DotRenderer(getApplicationContext(), googleMap, clusterManager,
                    lruCache, this.getFilesDir().toString());
    clusterManager.setRenderer(dotRenderer);
Run Code Online (Sandbox Code Playgroud)

随着每次屏幕旋转,内存不断增加,我放大的地图越多(显示的标记越多),当我旋转屏幕直到应用程序崩溃时,我的应用程序堆中添加的内存量就越多.

有时错误不像上面那样,但表明OOM发生在我的DefaultClusterRenderer<MyItam>扩展中的这一行markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));.

如果我禁用自定义标记图标(删除所有Bitmap相关代码),内存问题就会消失.请帮我找出导致这个OOM出现的原因.

Ris*_*pat 1

好吧...我想这应该可行...

googleMap.clear()每当您想要重置地图时添加。

希望对你有帮助。