资源$ NotFoundException for XML vector drawable on API 19

时间:2018-01-16 16:14:49

标签: android android-resources android-vectordrawable

我尝试使用以下代码加载XML vector vector:

int px = Application.get().getResources()
                .getDimensionPixelSize(R.dimen.bikeshare_small_marker_size);

Bitmap bitmap = Bitmap.createBitmap(px, px, Bitmap.Config.ARGB_8888);

Canvas c = new Canvas(bitmap);
Drawable shape = ContextCompat.getDrawable(Application.get(), R.drawable.bike_marker_small);
shape.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
shape.draw(c);

以下是bike_marker_small.xml文件:

<vector android:height="24dp" android:viewportHeight="210.0"
    android:viewportWidth="210.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#ffffff"
        android:pathData="M105.03,104.97m-53.84,0a53.84,53.84 117.34,1 1,107.67 0a53.84,53.84 117.34,1 1,-107.67 0"
        android:strokeAlpha="1" android:strokeColor="#3a4677" android:strokeWidth="1.46500003"/>
    <path android:fillAlpha="1" android:fillColor="#3a4677"
        android:pathData="M105.1,104.67m-47.53,0a47.53,47.53 118.07,1 1,95.06 0a47.53,47.53 118.07,1 1,-95.06 0"
        android:strokeAlpha="1" android:strokeColor="#000000" android:strokeWidth="0.26458332"/>
</vector>

在Android 6,7和8上,这很好用。但是,当我尝试在API 19(Android 4.4)模拟器或设备上运行应用程序时,我得到以下内容:

 android.content.res.Resources$NotFoundException: File res/drawable/bike_marker_small.xml from drawable resource ID #0x7f08005f. 
 If the resource you are trying to use is a vector resource, you may be referencing it in an unsupported way. 
 See AppCompatDelegate.setCompatVectorFromResourcesEnabled() for more info.
      at android.content.res.Resources.loadDrawable(Resources.java:2101)
      at android.content.res.Resources.getDrawable(Resources.java:700)
      at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:353)
      at org.onebusaway.android.map.googlemapsv2.bike.BikeStationOverlay.createBitmapFromShape(BikeStationOverlay.java:195)
      at org.onebusaway.android.map.googlemapsv2.bike.BikeStationOverlay.(BikeStationOverlay.java:87)
      at org.onebusaway.android.map.googlemapsv2.BaseMapFragment.setupBikeStationOverlay(BaseMapFragment.java:474)

我的build.gradle中有以下内容:

android {
    compileSdkVersion 27
    buildToolsVersion "26.0.2"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 86
        versionName "2.3.1"

        vectorDrawables.useSupportLibrary = true
    }
...

为什么这不起作用?

3 个答案:

答案 0 :(得分:9)

尝试使用shape代替VectorDrawableCompat.create()创建可绘制的ContextCompat.getDrawable()

Drawable shape = VectorDrawableCompat.create(
    Application.get().getResources(),
    R.drawable.bike_marker_small, 
    Application.get().getTheme()
);

答案 1 :(得分:1)

Sean Barbeau的回答肯定很棒,尽管我想补充一下发生在我身上的事情,这可能会给其他人带来麻烦,试图弄清楚API 19或API 20上的VectorDrawable是怎么回事

我创建了一种方法,用于在不需要/想要将VectorDrawable用作Drawable的情况下将Drawable用作Bitmap的情况例。此方法适用于> = API 19的Android版本。

这是Kotlin方法(请看最后的改进版本):

fun getDrawable(context:Context, drawableId: Int): Drawable {
    var drawable: Drawable?

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = VectorDrawableCompat.create(context.resources, drawableId, context.theme)
    } else {
        drawable = ContextCompat.getDrawable(context, drawableId)
    }

    return drawable
}

基本上,我传递上下文(因为该方法将是辅助方法,并且将在没有ContextActivity的类中)和VectorDrawable的资源ID

可能会发生,您可以使用R名称空间直接使用资源ID调用此辅助方法,如下所示:

ImageUtils.Companion.getDrawable(
    getBaseContext(),
    R.drawable.your_vector_drawable
)

但是,也可以动态生成资源ID,类似于:

@DrawableRes val resourceID = context.resources.getIdentifier(
    "resource_prefix_" + type,
    "drawable",
    context.packageName
)

然后使用resourceID变量,以与以前相同的方式调用helper方法:

ImageUtils.Companion.getDrawable(
    getBaseContext(),
    resourceID
)

如果以此方式进行操作,则在API <21上时,动态生成的资源ID很可能是PNG。并且辅助方法将失败,因为它期望使用XML(SVG)。您可以通过请求普通的Drawable(而不是VectorDrawable),捕获将要引发的NotFoundException并得到一个Drawable来解决此问题。这是最终的帮助方法:

fun getDrawable(context:Context, drawableId: Int): Drawable {
    var drawable: Drawable?
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        try {
            drawable = VectorDrawableCompat.create(context.resources, drawableId, context.theme)
        } catch (ex: Resources.NotFoundException) {
            drawable = ContextCompat.getDrawable(context, drawableId)
        }
    } else {
        drawable = ContextCompat.getDrawable(context, drawableId)
    }

    return drawable
}

答案 2 :(得分:0)

您应该使用AppCompatResources.getDrawable(context, R.drawable.drawable_id);来内部完成所有操作。

此功能适用于:

  1. 正常Drawables s
  2. VectorDrawable
  3. AnimatedVectorDrawable s
  4. AnimatedStateListDrawable s

您需要appcompat库才能做到这一点