Kuva Kuva - 2 months ago 30
Java Question

Android creating BitmapDescriptor exception

I'm writing an application that works alot with google map and markers on it. My task is to create and display some amount of markers on google map. Markers have custom image and text in it. Data is loading from server and i need to display new amount of data every time user moves google map camera. So i'm using android-maps-utils:0.4.3 library for creating custom Bitmap (using IconGenerator) and then create BitmapDescriptor from it. Here is part of the code:

googleMap.clear()

LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

IconGenerator clusterIconGenerator = new IconGenerator(getActivity());
View clusterView = layoutInflater.inflate(R.layout.marker_cluster_view, null, false);
clusterIconGenerator.setContentView(clusterView);
clusterIconGenerator.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.mark_normal_grey));

List<Cluster> clusters = result.getResult(); // server data

for (Cluster cluster : clusters) {
Bitmap bitmap = clusterIconGenerator.makeIcon(String.valueOf(cluster.getOffersCount()));

Marker marker = googleMap.addMarker(new MarkerOptions()
.position(new LatLng(cluster.getLocation().getLatitude(), cluster.getLocation().getLongitude()))
.icon(BitmapDescriptorFactory.fromBitmap(bitmap)) // crash here
.anchor(0.5f, 0.5f));

markerClusterMap.put(marker, cluster);
}


Everything is ok except application is crashes sometimes (not very often) with 2 different exceptions:

java.lang.RuntimeException: Could not copy bitmap to parcel blob.
at android.graphics.Bitmap.nativeWriteToParcel(Native Method)
at android.graphics.Bitmap.writeToParcel(Bitmap.java:1541)
at com.google.android.gms.maps.model.a.c.a(:com.google.android.gms:237)
at com.google.android.gms.maps.internal.h.a(:com.google.android.gms:227)
at com.google.android.gms.maps.internal.j.a(:com.google.android.gms:183)
at com.google.android.gms.maps.internal.CreatorImpl.a(:com.google.android.gms:32)
at com.google.android.gms.maps.internal.b.a(:com.google.android.gms:227)
at com.google.android.gms.maps.model.a.b.onTransact(:com.google.android.gms:106)
at android.os.Binder.transact(Binder.java:387)
at com.google.android.gms.maps.model.internal.zza$zza$zza.zzc(Unknown Source)
at com.google.android.gms.maps.model.BitmapDescriptorFactory.fromBitmap(Unknown Source)
at com.cheapsta.cheapsta.fragments.GoogleMapFragment.clustersLoadingFinished(GoogleMapFragment.java:187)


and sometimes

java.lang.RuntimeException: Could not allocate dup blob fd.
at android.graphics.Bitmap.nativeCreateFromParcel(Native Method)
at android.graphics.Bitmap.-wrap0(Bitmap.java)
at android.graphics.Bitmap$1.createFromParcel(Bitmap.java:1516)
at android.graphics.Bitmap$1.createFromParcel(Bitmap.java:1515)
at maps.bx.a$a.onTransact(:com.google.android.gms.alldynamite:101)
at android.os.Binder.transact(Binder.java:387)
at com.google.android.gms.maps.model.a.c.a(:com.google.android.gms:242)
at com.google.android.gms.maps.internal.h.a(:com.google.android.gms:227)
at com.google.android.gms.maps.internal.j.a(:com.google.android.gms:183)
at com.google.android.gms.maps.internal.CreatorImpl.a(:com.google.android.gms:32)
at com.google.android.gms.maps.internal.b.a(:com.google.android.gms:227)
at com.google.android.gms.maps.model.a.b.onTransact(:com.google.android.gms:106)
at android.os.Binder.transact(Binder.java:387)
at com.google.android.gms.maps.model.internal.zza$zza$zza.zzc(Unknown Source)
at com.google.android.gms.maps.model.BitmapDescriptorFactory.fromBitmap(Unknown Source)
at com.cheapsta.cheapsta.fragments.GoogleMapFragment.clustersLoadingFinished(GoogleMapFragment.java:187)


What can i do with this? I guess i'm using my memory to much to create BitmapDescriptors. It's nearly 20 BitmapDescriptos every 3 seconds if user moving camera too much. Should i cache it somehow? Thx a lot for your answers and time!

Answer

Well here is what i got. Looks like BitmapFactory can't create Bitmap if it don't have enought memory. So if GC didn't do job and u don't have enough memory u'll get this exception. In my case that was pretty often because i need to generate about 10-20 markers every time user moves google map camera.

First of all don't be stupid like me and don't use android-maps-utils just for IconGenerator :) I wrote my own class that generate's BitmapDescriptor from Bitmap and caches it in LruCache. Here's good tutorial for caching Bitmaps. You can do almost the same for BitmapDescriptor. Pay attention to LruCache size. You can't get BitmapDescriptor size in bytes, so you need to think about amount of these objects in LruCache. Just look at your bitmap size and do some calculations.

If you need text in your image do something like this:

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.mark_active_grey).copy(Bitmap.Config.ARGB_8888, true);

    Canvas canvas = new Canvas(bitmap);
    canvas.drawText(offersCount,
            canvas.getWidth()/2,
            canvas.getHeight()/2 - ((clustersPaint.getFontMetrics().ascent + clustersPaint.getFontMetrics().descent) / 2) ,
            clustersPaint);

Sorry for bad english and i hope this information will be useful to some one.