Android throws BitmapDescriptor exception

I am writing an application that works with google maps and markers. My task is to create and display a number of markers on a Google map. Markers have a custom image and text. Data is downloaded from the server, and I need to display a new amount of data every time a user moves a Google Map. So I use the android-maps-utils: 0.4.3 library to create a custom Bitmap (using IconGenerator), and then create a BitmapDescriptor from it. Here is the piece of 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 in order, except that the application sometimes (sometimes not often) crashes with two 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.aca(:com.google.android.gms:237) at com.google.android.gms.maps.internal.ha(:com.google.android.gms:227) at com.google.android.gms.maps.internal.ja(: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.ba(:com.google.android.gms:227) at com.google.android.gms.maps.model.abonTransact(: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.aca(:com.google.android.gms:242) at com.google.android.gms.maps.internal.ha(:com.google.android.gms:227) at com.google.android.gms.maps.internal.ja(: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.ba(:com.google.android.gms:227) at com.google.android.gms.maps.model.abonTransact(: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 think I use my memory to create BitmapDescriptors. This is almost 20 BitmapDescriptos every 3 seconds if the user moves the camera too much. Do I have to cache it somehow? Thanks a lot for your answers and time!

+3
source share
4 answers

Ok that's what I got. It seems that BitmapFactory cannot create Bitmap if it does not have enough memory. So if the GC wasn’t doing the work and you have insufficient memory, you will get this exception. In my case, this was quite common, because I need to generate about 10-20 markers every time a user moves a Google Maps map.

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

If you need text on 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 the bad English, and I hope this information is useful to someone.

+4
source

I had the same problem. With Kuva's answer, I am making a new class as follows:

 public class MapBmpContainter { private int mBmpSize; public BitmapDescriptor mBmpDescriptor; public MapBmpContainter(Bitmap bmp) { mBmpSize=bmp.getByteCount()/1014; mBmpDescriptor= BitmapDescriptorFactory.fromBitmap(bmp); } public int getSize() { return mBmpSize; } } 

I am caching a new class object in LruCache instead of Bitmap. Same with Kuva. I think Bitmap and BitmapDescriptor are almost the same size. And he worked

+1
source

For me, the problem is with the size of the icon. I just dynamically resize the bitmap and work fine.

Bitmap image2 = Bitmap.createScaledBitmap (iconBitmap, 120, 120, false);

0
source

Use Picasso, Glide or Fresco Literary to efficiently cache bitmaps.

  Picasso.with(getContext()) .load(R.drawable.marker) .resize(width, width) .into(new Target() { @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { markerOptionsHome = new MarkerOptions(); markerOptionsHome.title("Home location"); markerOptionsHome.snippet(""); markerOptionsHome.position(latlng); markerOptionsHome.icon(BitmapDescriptorFactory.fromBitmap(bitmap)); homeLocationMarker = map.addMarker(markerOptionsHome); } @Override public void onBitmapFailed(Drawable errorDrawable) { } @Override public void onPrepareLoad(Drawable placeHolderDrawable) { } }); 
-1
source

Source: https://habr.com/ru/post/1268079/


All Articles