15

ich habe ein großes speicherproblem in meiner app. Ich benutze Google Map API v2 mit ClusterManager und benutzerdefinierte Markierungen. Ich gebe ein Bild per Anruf an markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap)); für jeden Marker basierend auf seiner Kategorie. das Problem ist: nach mehreren Drehungen Bildschirm meiner App abstürzt wegen OOM-Fehler:google maps api v2 aus speicherfehler

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) 

ich habe ein LruCache Objekt mit meinem Bitmap s, es bedeutet, dass ich sie nicht neu, aber sie wiederzuverwenden. Ich kann klar sehen, dass jedes Bitmap Objekt aus dem Cache, nicht von anderswo genommen wird. Wenn die Bitmap jedoch noch nicht im Cache ist (beim ersten Laden), lade ich sie aus dem internen Speicher meiner App, aber es funktioniert nur, wenn die Bitmap das erste Mal gestartet wird. Ich behalte die Instanz der LruCache in einer beibehaltenen Fragment Instanz und übergeben Sie es an meine benutzerdefinierte DefaultClusterRenderer<MyObject> Objekt jedes Mal, wenn die Activity neu erstellt wird und Karte neu gezeichnet werden muss.

das ist mein DefaultClusterRenderer<MyItem> Erweiterung:

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

Dies ist der Code in meinem Activity, wo ich die Karte starten Laden (dieser Code jedes Mal Bildschirmausrichtung ändert ausgeführt wird):

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

der Speicher Mit jeder Drehung des Bildschirms nimmt der Wert zu. Je mehr ich die Karte zoome (je mehr Markierungen angezeigt werden), desto mehr Speicher wird dem Heap meiner App hinzugefügt, wenn ich den Bildschirm rotiere, bis die Anwendung abstürzt.

manchmal ist der Fehler nicht wie oben, aber zeigt, dass OOM in dieser Zeile in meiner DefaultClusterRenderer<MyItam> Extension markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap)); passiert ist.

Wenn ich benutzerdefinierte Marker-Symbol deaktivieren (entfernen Sie alle Bitmap bezogenen Code) das Speicherproblem verschwindet. Bitte helfen Sie mir zu finden, was diese OOM verursacht.

+0

Haben Sie diese auf Ihrer Hauptaktivität ausprobiert? @Override public void onLowMemory() { super.onLowMemory(); mapView.onLowMemory(); } Ich meine in der Aktivität oder Fragment, die die Kartenansicht hinzugefügt ... –

+0

habe ich was probiert? – Salivan

+0

Kommentar bearbeitet .. überprüfen Sie es ... –

Antwort

0

Okay ... ich denke, das sollte funktionieren ...

googleMap.clear() hinzufügen, wenn Sie die Karte zurücksetzen möchten.

Hoffe, das wird Ihnen helfen.

+0

bereits versucht, dies auch . kein Glück. Ich habe sogar versucht, das Symbol für jeden Marker einzeln auf Standard zu setzen und sie dann einzeln in 'Activity's 'onDestroy()' zu entfernen. – Salivan

0

Dies ist der Bug von Google Maps V2. Google einige Ausgabe .Der Bug Problem lösen ist Here

dieses Problem erholen Sie diese Schritte folgen:

<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" /> 

Nehmen Instanz von Google Map:

XML diese mögen `` GoogleMap atmFinderMap;

  1. Vor dem Initialisieren des Kartenanrufs System.gc(); und getMap().(Clear); `

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

Set Karte als wie folgt aus:

SupportMapFragment fragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.frYourMap); 
    atmFinderMap = fragment.getMap(); 
  1. verwenden überschrieben Methode:

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

Weitere Informationen finden Sie unter this answer

+0

Ich habe darüber gelesen, aber ist es nicht schon behoben? Posts zu diesem Bug sind alt (Jahr 2013) und ich habe einige offizielle Google-Posts gelesen, dass Bugs im Zusammenhang mit Speicherlecks mit Google Play Services v3 behoben wurden. meine Symptome sind jedoch alle gleich, wie in all den Posts beschrieben, die mit diesem Bug zusammenhängen ... – Salivan

+0

Sie haben Recht, Sir.Eine Reihe von Speicherlecks wurden in der neuesten Version der Google Maps Android API behoben. –

+0

Worüber reden Sie also, wenn Sie sagen, dass Speicherlecks behoben wurden? meinst du, dass nicht alle von ihnen repariert wurden? Könnten Sie mir die Quelle dieser Information zeigen? – Salivan

2

Ich habe dieses Problem beim Versuch, eine App im Demo-Modus für ein paar Stunden zu einer Zeit zu laufen. Egal was ich versuchte, nach 30 Minuten würde ich diesen Absturz ohne einen lesbaren Stapelbericht sehen.

Ich habe versucht, System gc(), das Fragment, Singleton-Aktivitäten zu lösen, Google Play-Dienste auf den neuesten Stand zu bringen, Verweise auf Overlays zu löschen, Kartenlebenszyklus an Aktivität anhängen und was nicht. Nach vielen gescheiterten Versuchen und viel Frust fand ich endlich etwas, das funktionierte. Es ist keine Lösung für den Kartenfehler, aber es hat meine App vor dem Absturz bewahrt:

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

das funktionierte für mich – Veer

+1

Ich verbrachte Stunden, bevor Sie in diesen Thread stoßen. Ich habe eine Kombination der drei Antworten verwendet: largeHeap, System.gc und map.clear. Es funktionierte – FabioC

Verwandte Themen