【问题标题】:Resources$NotFoundException for XML vector drawable on API 19在 API 19 上可绘制 XML 矢量的 Resources$NotFoundException
【发布时间】:2018-01-16 16:14:49
【问题描述】:

我正在尝试使用以下代码加载可绘制的 XML 向量:

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
    }
...

为什么这不起作用?

【问题讨论】:

    标签: android android-resources android-vectordrawable


    【解决方案1】:

    尝试使用VectorDrawableCompat.create() 而不是ContextCompat.getDrawable() 创建drawable shape

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

    【讨论】:

    • 你在 4 分钟前问过,你在 4 分钟前回答了自己……真的吗?
    • 是的,鼓励使用这种格式 - 请参阅 stackoverflow.com/help/self-answer。我没有得到任何积分,但至少通过这种方式记录下来供其他人找到答案。
    • 顺便说一句 - @AlexTa 你对这个问题投了反对票吗?它有两个没有评论的反对票,我不明白为什么。
    • 不,我没有。我只对垃圾邮件或辱骂性问题/答案投反对票。
    • 伟大的自我回答!对问题和答案都投了赞成票。
    【解决方案2】:

    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
    )
    

    然后调用 helper 方法,和之前一样,使用 resourceID 变量:

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

    如果您这样做,在 API 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
    }
    

    【讨论】:

      【解决方案3】:

      您应该使用AppCompatResources.getDrawable(context, R.drawable.drawable_id);,它会在内部为您解决所有问题。

      这适用于:

      1. 正常Drawabless
      2. VectorDrawables,
      3. AnimatedVectorDrawables
      4. AnimatedStateListDrawables

      您需要 appcompat 库来执行此操作

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-19
        • 2018-06-10
        • 1970-01-01
        • 1970-01-01
        • 2019-04-29
        • 2021-01-06
        相关资源
        最近更新 更多