I have problem with google maps BitmapDescriptor
while creating icon for MarkerOptions
using VectorDrawable
, API 5.0+
Method used for creation:
@NonNull
private BitmapDescriptor getBitmapDescriptor(int id) {
return BitmapDescriptorFactory.fromResource(id);
}
Everything works great when id
argument contains png drawable, however if I try it with VectorDrawable
defined in xml, App always crash when googleMap.addMarker(marker)
(BitmapDescriptor
is not null).
11-05 10:15:05.213 14536-14536/xxx.xxxxx.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: xxx.xxxxx.app, PID: 14536
java.lang.NullPointerException
at com.google.a.a.ae.a(Unknown Source)
at com.google.maps.api.android.lib6.d.dn.<init>(Unknown Source)
at com.google.maps.api.android.lib6.d.dm.a(Unknown Source)
at com.google.maps.api.android.lib6.d.ag.<init>(Unknown Source)
at com.google.maps.api.android.lib6.d.eu.a(Unknown Source)
at com.google.android.gms.maps.internal.j.onTransact(SourceFile:167)
at android.os.Binder.transact(Binder.java:380)
at com.google.android.gms.maps.internal.IGoogleMapDelegate$zza$zza.addMarker(Unknown Source)
at com.google.android.gms.maps.GoogleMap.addMarker(Unknown Source)
at xxx.xxxxx.app.ui.details.DetailActivity.lambda$initGoogleMaps$23(DetailActivity.java:387)
at xxx.xxxxx.app.ui.details.DetailActivity.access$lambda$10(DetailActivity.java)
at xxx.xxxxx.app.ui.details.DetailActivity$$Lambda$13.onMapReady(Unknown Source)
at com.google.android.gms.maps.SupportMapFragment$zza$1.zza(Unknown Source)
at com.google.android.gms.maps.internal.zzl$zza.onTransact(Unknown Source)
at android.os.Binder.transact(Binder.java:380)
at com.google.android.gms.maps.internal.av.a(SourceFile:82)
at com.google.maps.api.android.lib6.d.fa.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
It doesn't matter how i retrieve drawable, tried creating bitmap using BitmapFactory.fromResources
and later BitmapDescritpionFactory.fromBitmap
but results are the same. It just won't work with vector drawable. Tried different vectors as well but it's seems that vector complexity is not the issue here.
Does anyone know how to fix this crash?
@edit
It seems like the problem wasn't with the BitmapDescriptior
itself, but rather with loading VectorDrawable
which was returning incorrect bitmap. However solution proposed in answer is still fine.
Possible workaround:
private BitmapDescriptor getBitmapDescriptor(int id) {
Drawable vectorDrawable = context.getDrawable(id);
int h = ((int) Utils.convertDpToPixel(42, context));
int w = ((int) Utils.convertDpToPixel(25, context));
vectorDrawable.setBounds(0, 0, w, h);
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
vectorDrawable.draw(canvas);
return BitmapDescriptorFactory.fromBitmap(bm);
}
According to the bug report (posted by vaughandroid - thanks!) using a VectorDrawable won't be supported for the time being. See the comment in the bug report for more information.
Here's the suggested workaround from the Google Maps team:
/**
* Demonstrates converting a {@link Drawable} to a {@link BitmapDescriptor},
* for use as a marker icon.
*/
private BitmapDescriptor vectorToBitmap(@DrawableRes int id, @ColorInt int color) {
Drawable vectorDrawable = ResourcesCompat.getDrawable(getResources(), id, null);
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
DrawableCompat.setTint(vectorDrawable, color);
vectorDrawable.draw(canvas);
return BitmapDescriptorFactory.fromBitmap(bitmap);
}
used this way:
// Vector drawable resource as a marker icon.
mMap.addMarker(new MarkerOptions()
.position(ALICE_SPRINGS)
.icon(vectorToBitmap(R.drawable.ic_android, Color.parseColor("#A4C639")))
.title("Alice Springs"));
Tinting of the vector is a bonus
Or you could simply use Android KTX
e.g:
val markerBitmap = ResourcesCompat.getDrawable(resources, R.drawable.ic_marker, null)?.toBitmap()
val icon = BitmapDescriptorFactory.fromBitmap(markerBitmap)
val marker = MarkerOptions().icon(icon)
Reference: .toBitmap()
Here is another reference: http://qiita.com/konifar/items/aaff934edbf44e39b04a
public class ResourceUtil {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vectorDrawable.draw(canvas);
return bitmap;
}
private static Bitmap getBitmap(VectorDrawableCompat vectorDrawable) {
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vectorDrawable.draw(canvas);
return bitmap;
}
public static Bitmap getBitmap(Context context, @DrawableRes int drawableResId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableResId);
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof VectorDrawableCompat) {
return getBitmap((VectorDrawableCompat) drawable);
} else if (drawable instanceof VectorDrawable) {
return getBitmap((VectorDrawable) drawable);
} else {
throw new IllegalArgumentException("Unsupported drawable type");
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With