Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VectorDrawable with GoogleMap BitmapDescriptor

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.

like image 772
Than Avatar asked Nov 05 '15 15:11

Than


4 Answers

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);
}
like image 183
Than Avatar answered Nov 11 '22 02:11

Than


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

like image 34
lbarbosa Avatar answered Nov 11 '22 02:11

lbarbosa


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

like image 11
Rodrigo Queiroz Avatar answered Nov 11 '22 01:11

Rodrigo Queiroz


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");
    }
}
}
like image 6
TeeTracker Avatar answered Nov 11 '22 01:11

TeeTracker