XML 在 API 19 上可绘制的矢量的 Resources$NotFoundException
Resources$NotFoundException for XML vector drawable on API 19
我正在尝试使用以下代码加载 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
}
...
为什么这不起作用?
尝试使用 VectorDrawableCompat.create()
而不是 ContextCompat.getDrawable()
创建可绘制对象 shape
:
Drawable shape = VectorDrawableCompat.create(
Application.get().getResources(),
R.drawable.bike_marker_small,
Application.get().getTheme()
);
Sean Barbeau 的回答绝对很棒,尽管我想补充一些发生在我身上的事情,这可能会给其他试图弄清楚 VectorDrawable
在 [=45] 上发生了什么的人带来麻烦=] 19 或 API 20.
我创建了一个方法来获得 VectorDrawable
作为 Drawable
的情况,当我不 need/want 将它们用作 Drawable
,而是作为 [=19] =],例如。此方法适用于 Android 版本 >= API 19.
这是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
}
基本上,我传递了上下文(因为这个方法将是一个辅助方法,并且将在 class 中,没有 Context
或 Activity
)和资源 ID VectorDrawable
.
您可能会使用 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 < 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
}
你应该使用 AppCompatResources.getDrawable(context, R.drawable.drawable_id);
,它在内部为你完成了所有的技巧。
这适用于:
- 正常
Drawables
s
VectorDrawable
s,
AnimatedVectorDrawable
s
AnimatedStateListDrawable
s
您需要 appcompat 库来执行此操作
我正在尝试使用以下代码加载 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
}
...
为什么这不起作用?
尝试使用 VectorDrawableCompat.create()
而不是 ContextCompat.getDrawable()
创建可绘制对象 shape
:
Drawable shape = VectorDrawableCompat.create(
Application.get().getResources(),
R.drawable.bike_marker_small,
Application.get().getTheme()
);
Sean Barbeau 的回答绝对很棒,尽管我想补充一些发生在我身上的事情,这可能会给其他试图弄清楚 VectorDrawable
在 [=45] 上发生了什么的人带来麻烦=] 19 或 API 20.
我创建了一个方法来获得 VectorDrawable
作为 Drawable
的情况,当我不 need/want 将它们用作 Drawable
,而是作为 [=19] =],例如。此方法适用于 Android 版本 >= API 19.
这是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
}
基本上,我传递了上下文(因为这个方法将是一个辅助方法,并且将在 class 中,没有 Context
或 Activity
)和资源 ID VectorDrawable
.
您可能会使用 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 < 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
}
你应该使用 AppCompatResources.getDrawable(context, R.drawable.drawable_id);
,它在内部为你完成了所有的技巧。
这适用于:
- 正常
Drawables
s VectorDrawable
s,AnimatedVectorDrawable
sAnimatedStateListDrawable
s
您需要 appcompat 库来执行此操作