Google maps api v2 ошибка памяти

У меня огромная проблема с памятью в моем приложении. Я использую google map 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)

У меня есть объект LruCache с моим Bitmap s, это значит, что я не воссоздаю их, а повторно их использую. я могу ясно видеть, что каждый объект 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);
}
}

это код внутри моего 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);

память увеличивается с каждым поворотом экрана, чем больше я масштабирую карту (чем больше маркеров отображается), тем больше объема памяти добавляется в мою кучу приложения, когда я поворачиваю экран до тех пор, пока приложение не сработает.

иногда ошибка не такая, как показано выше, но показывает, что OOM произошла в этой строке в расширении DefaultClusterRenderer<MyItam> markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));.

Если я отключу значок пользовательского маркера (удалите весь связанный код Bitmap), проблема с памятью исчезнет. пожалуйста, помогите мне найти причину появления этого OOM.

Ответы

Ответ 1

Я столкнулся с этой проблемой, пытаясь запустить приложение в демонстрационном режиме несколько часов за раз. Независимо от того, что я пробовал, через 30 минут я увижу этот сбой без отчетного отчета о стеке.

Я попробовал System gc(), отделив фрагмент, действия Singleton, обновив сервисы google play до последних, очистив ссылки на наложения, привязав жизненный цикл карты к действию, а что нет. После многих неудачных попыток и большого разочарования я наконец нашел что-то, что сработало. Это не ошибка для ошибки карты, но она не позволяет моему приложению сбой:

    <application
    ...
    android:largeHeap="true">

Ответ 2

Хорошо... Я думаю, что это должно сработать...

Добавьте googleMap.clear(), когда хотите reset карту.

Надеюсь, это поможет вам.

Ответ 3

Это ошибка Google maps V2. Google разрешает проблему. Проблема с ошибкой Здесь

Чтобы восстановить эту проблему, вы можете выполнить следующие действия:

XML будет выглядеть следующим образом:

<fragment
    android:id="@+id/frYourMap"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    class="com.google.android.gms.maps.SupportMapFragment" />

Возьмите экземпляр Карты Google: `` GoogleMap atmFinderMap;

  • Перед инициализацией вызова карты System.gc(); и getMap(). clear(); `

    if(GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) == ConnectionResult.SUCCESS) {
        System.gc(); getMap().clear();}
    

установить карту следующим образом:

SupportMapFragment fragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.frYourMap);
    atmFinderMap = fragment.getMap();
  1. Используйте этот перезаписанный метод:

    @Override
    public void onLowMemory() {
    super.onLowMemory();
    System.gc();
    }
    

Чтобы получить дополнительную информацию, вы можете увидеть этот ответ