android.view.InflateException 使用 selectableItemBackground 时
android.view.InflateException when using selectableItemBackground
在为我的布局充气时,我得到这个异常:
E AndroidRuntime: android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class <unknown>
E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
E AndroidRuntime: at com.myapp.view.MyRecyclerAdapter.onCreateViewHolder(MyRecyclerAdapter:80)
E AndroidRuntime: at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:5288)
E AndroidRuntime: at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4551)
E AndroidRuntime: at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4461)
E AndroidRuntime: at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1962)
日志中没有 "Caused by",但我添加了代码来捕获异常并调用 getCause()
直到它 returns 为 null,事件顺序如下:
android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class <unknown>
android.view.InflateException: Binary XML file line #11: Error inflating class <unknown>
Error: Binary XML file line #11: Error inflating class <unknown>
android.content.res.Resources$NotFoundException: File res/drawable-v11/selectable_list_background.xml from drawable resource ID #0x7f020096
java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f0100f9 a=-1}
0x7f020096 是 selectable_list_background
(见下文),它引用的 TypedValue 是 ?selectableItemBackground
.
我将异常缩小到我对 ?selectableItemBackground
的使用。更具体地说,我正在使用 CardView:
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@drawable/selectable_list_background"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
>
这是 drawable/selectable_list_background
的相关部分:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?selectableItemBackground" />
</selector>
这个activity使用的是我自己的主题,它的父主题是Theme.AppCompat.Light.NoActionBar
。
这段代码曾经可以运行,但是我几个月后才挖出这段代码,现在它崩溃并出现异常。我的猜测是这与将支持库升级到 23.0.1 并将目标 SDK 升级到 23 有关,但我还没有切换回 22 来验证。
如果我删除引用 ?selectableItemBackground
的一行,一切正常。我也尝试了 ?attr/selectableItemBackground
和 ?android:attr/selectableItemBackground
,但得到了相同的结果。 (后者让我相信这可能不是支持库的问题)。
编辑:
我在调试器里看了一下,怀疑是android.content.res.Resources
里的这段代码,里面loadDrawable()
:
Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
[...]
dr = loadDrawableForCookie(value, id, null);
注意这个函数接受了一个主题,但是在调用loadDrawableForCookie()
的时候没有传入,也就是最终触发第一个异常的方法:
java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f0100f9 a=-1}
at android.content.res.TypedArray.getDrawable(TypedArray.java:867)
at android.graphics.drawable.StateListDrawable.inflateChildElements(StateListDrawable.java:170)
at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:115)
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:1215)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:1124)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:2630)
at android.content.res.Resources.loadDrawable(Resources.java:2540)
at android.content.res.TypedArray.getDrawable(TypedArray.java:870)
at android.view.View.<init>(View.java:4280)
这段代码似乎是 Android 6.0 的新代码 - 5.0 的代码有很大不同,但主题是在加载 drawable 时传入的。并且主题是必要的 AFAICT - 有问题的属性是 AppCompat
的一部分,因此它需要 activity 的主题来解决它。
尽管这似乎是一个明显的错误,所以我不相信我在正确的轨道上。有什么想法吗?
官方答案 - 您不能将主题属性用于 android:drawable
或 android:src
属性。根本不可能,设计使然。还有另一个答案探讨了同样的问题并提供了解决方案:How to reference style attributes from a drawable?
就我而言,我无法真正做到这一点,因为 AppCompat 的 ?selectableItemBackground
引用了私有可绘制对象。所以我选择了一个代码解决方案 - 我将前景设置为 ?selectableItemBackground
而卡片未被选中,并且一旦我处于选择模式就可以绘制我自己的状态列表。
这是一个非常丑陋的解决方案,丑陋到我不打算在这里分享代码,但这是迄今为止我能想到的最好的解决方案。如果有人有更好的解决方案,我很乐意听到。
正如@Artjom 所说,问题在于在创建自定义视图时传递 application context
。我也遇到了同样的问题,我传递的是 getApplicationContext()
而不是 activity
作为 context
。通过 Activity
作为 context
问题解决后。
希望对其他人有所帮助。
不幸的是,其他答案不是我的情况。对我有用的方法是检查你的 activity 是否使用 AppCompat 主题风格:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
</style>
然后在你的 activity 中使用 AppCompat 主题(在很多方面,但我展示了使用 Manifest 的方法):
<application
android:name=".Abbott"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- Any configuration inside -->
</application>
我在使用androidx Fragment Testing 组件时出现了同样的错误。默认launchFragmentInContainer()
使用主题FragmentScenarioEmptyFragmentActivityTheme
,导致错误。
简单的解决方法是使用您自己的扩展 AppCompat 的主题:
launchFragmentInContainer(theme = R.style.AppTheme)
在为我的布局充气时,我得到这个异常:
E AndroidRuntime: android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class <unknown>
E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
E AndroidRuntime: at com.myapp.view.MyRecyclerAdapter.onCreateViewHolder(MyRecyclerAdapter:80)
E AndroidRuntime: at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:5288)
E AndroidRuntime: at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4551)
E AndroidRuntime: at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4461)
E AndroidRuntime: at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1962)
日志中没有 "Caused by",但我添加了代码来捕获异常并调用 getCause()
直到它 returns 为 null,事件顺序如下:
android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class <unknown>
android.view.InflateException: Binary XML file line #11: Error inflating class <unknown>
Error: Binary XML file line #11: Error inflating class <unknown>
android.content.res.Resources$NotFoundException: File res/drawable-v11/selectable_list_background.xml from drawable resource ID #0x7f020096
java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f0100f9 a=-1}
0x7f020096 是 selectable_list_background
(见下文),它引用的 TypedValue 是 ?selectableItemBackground
.
我将异常缩小到我对 ?selectableItemBackground
的使用。更具体地说,我正在使用 CardView:
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@drawable/selectable_list_background"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
>
这是 drawable/selectable_list_background
的相关部分:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?selectableItemBackground" />
</selector>
这个activity使用的是我自己的主题,它的父主题是Theme.AppCompat.Light.NoActionBar
。
这段代码曾经可以运行,但是我几个月后才挖出这段代码,现在它崩溃并出现异常。我的猜测是这与将支持库升级到 23.0.1 并将目标 SDK 升级到 23 有关,但我还没有切换回 22 来验证。
如果我删除引用 ?selectableItemBackground
的一行,一切正常。我也尝试了 ?attr/selectableItemBackground
和 ?android:attr/selectableItemBackground
,但得到了相同的结果。 (后者让我相信这可能不是支持库的问题)。
编辑:
我在调试器里看了一下,怀疑是android.content.res.Resources
里的这段代码,里面loadDrawable()
:
Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
[...]
dr = loadDrawableForCookie(value, id, null);
注意这个函数接受了一个主题,但是在调用loadDrawableForCookie()
的时候没有传入,也就是最终触发第一个异常的方法:
java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f0100f9 a=-1}
at android.content.res.TypedArray.getDrawable(TypedArray.java:867)
at android.graphics.drawable.StateListDrawable.inflateChildElements(StateListDrawable.java:170)
at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:115)
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:1215)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:1124)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:2630)
at android.content.res.Resources.loadDrawable(Resources.java:2540)
at android.content.res.TypedArray.getDrawable(TypedArray.java:870)
at android.view.View.<init>(View.java:4280)
这段代码似乎是 Android 6.0 的新代码 - 5.0 的代码有很大不同,但主题是在加载 drawable 时传入的。并且主题是必要的 AFAICT - 有问题的属性是 AppCompat
的一部分,因此它需要 activity 的主题来解决它。
尽管这似乎是一个明显的错误,所以我不相信我在正确的轨道上。有什么想法吗?
官方答案 - 您不能将主题属性用于 android:drawable
或 android:src
属性。根本不可能,设计使然。还有另一个答案探讨了同样的问题并提供了解决方案:How to reference style attributes from a drawable?
就我而言,我无法真正做到这一点,因为 AppCompat 的 ?selectableItemBackground
引用了私有可绘制对象。所以我选择了一个代码解决方案 - 我将前景设置为 ?selectableItemBackground
而卡片未被选中,并且一旦我处于选择模式就可以绘制我自己的状态列表。
这是一个非常丑陋的解决方案,丑陋到我不打算在这里分享代码,但这是迄今为止我能想到的最好的解决方案。如果有人有更好的解决方案,我很乐意听到。
正如@Artjom 所说,问题在于在创建自定义视图时传递 application context
。我也遇到了同样的问题,我传递的是 getApplicationContext()
而不是 activity
作为 context
。通过 Activity
作为 context
问题解决后。
希望对其他人有所帮助。
不幸的是,其他答案不是我的情况。对我有用的方法是检查你的 activity 是否使用 AppCompat 主题风格:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
</style>
然后在你的 activity 中使用 AppCompat 主题(在很多方面,但我展示了使用 Manifest 的方法):
<application
android:name=".Abbott"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- Any configuration inside -->
</application>
我在使用androidx Fragment Testing 组件时出现了同样的错误。默认launchFragmentInContainer()
使用主题FragmentScenarioEmptyFragmentActivityTheme
,导致错误。
简单的解决方法是使用您自己的扩展 AppCompat 的主题:
launchFragmentInContainer(theme = R.style.AppTheme)