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();
-
Используйте этот перезаписанный метод:
@Override
public void onLowMemory() {
super.onLowMemory();
System.gc();
}
Чтобы получить дополнительную информацию, вы можете увидеть этот ответ