web-dev-qa-db-fra.com

google maps api v2 erreur de mémoire

j'ai un énorme problème de mémoire dans mon application. J'utilise google map api v2 avec ClusterManager et des marqueurs personnalisés. Je fournis une image par appel à markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap)); pour chaque marqueur en fonction de sa catégorie. le problème est le suivant: après plusieurs rotations d'écran, mon application se bloque à cause d'une erreur de MOO:

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)

j'ai un objet LruCache avec mon Bitmaps, cela signifie que je ne les recrée pas, mais les réutilise. Je peux clairement voir que chaque objet Bitmap est extrait du cache et non d’ailleurs. Cependant, si la Bitmap n'est pas encore dans le cache (premier chargement), je la charge à partir de la mémoire interne de mon application, mais cela ne se produit que lorsque la Bitmap est copiée pour la première fois. Je garde l'instance de LruCache dans une instance Fragment conservée et la passe à mon objet DefaultClusterRenderer<MyObject> personnalisé à chaque fois que la Activity est recréée et que la carte doit être redessinée.

c'est mon extension 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);
}
}

voici le code dans ma Activity où je commence à charger la carte (ce code est exécuté chaque fois que l'orientation de l'écran change):

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

la mémoire ne cessant d'augmenter avec chaque rotation d'écran, plus je zoome sur la carte (plus de marqueurs sont affichés), plus la quantité de mémoire ajoutée à la mémoire de mon application est importante lorsque je fais pivoter l'écran jusqu'à ce que l'application se bloque.

parfois, l'erreur n'est pas comme ci-dessus, mais montre que le MOO est arrivé à cette ligne dans mon DefaultClusterRenderer<MyItam> extension markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));.

si je désactive l’icône de marqueur personnalisé (supprime tout le code associé à Bitmap), le problème de mémoire disparaît. aidez-moi s'il vous plaît à trouver ce qui fait apparaître ce MOO.

16
Salivan

J'ai rencontré ce problème en essayant d'exécuter une application en mode démo pendant quelques heures à la fois. Peu importe ce que j'ai essayé, après 30 minutes, je verrais ce blocage sans rapport de pile lisible.

J'ai essayé System gc (), détachant le fragment, activités singleton, mettant à jour les services de Google Play les plus récents, effaçant les références aux surimpressions, associant le cycle de vie des cartes à une activité ou autre. Après de nombreuses tentatives infructueuses et beaucoup de frustration J'ai finalement trouvé quelque chose qui a fonctionné. Ce n'est pas un correctif pour le bogue de carte, mais cela a empêché mon application de planter:

    <application
    ...
    Android:largeHeap="true">
1
TacoEater

D'accord ... Je pense que cela devrait fonctionner ...

Ajoutez googleMap.clear() chaque fois que vous souhaitez réinitialiser la carte.

J'espère que ceci vous aidera.

0
Rishad Appat