使用BottomSheetBehavior时报错 :java.lang.UnsupportedOperationException

问题背景

在一个普通的activity中使用 com.google.android.material.bottomsheet.BottomSheetBehavior报错内容

css 复制代码
java.lang.UnsupportedOperationException: Failed to resolve attribute at index 3: TypedValue{t=0x2/d=0x7f04013f a=5}
 Caused by: java.lang.RuntimeException: Could not inflate Behavior subclass com.google.android.material.bottomsheet.BottomSheetBehavior
                                                 	at androidx.coordinatorlayout.widget.CoordinatorLayout.parseBehavior(CoordinatorLayout.java:649)
                                                 	at androidx.coordinatorlayout.widget.CoordinatorLayout$LayoutParams.<init>(CoordinatorLayout.java:2896)
                                                 	at androidx.coordinatorlayout.widget.CoordinatorLayout.generateLayoutParams(CoordinatorLayout.java:1740)
                                                 	at androidx.coordinatorlayout.widget.CoordinatorLayout.generateLayoutParams(CoordinatorLayout.java:112)
                                                 	at android.view.LayoutInflater.rInflate(LayoutInflater.java:1150)
                                                 	at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1109)
                                                 	at android.view.LayoutInflater.inflate(LayoutInflater.java:707)
                                                 	at android.view.LayoutInflater.inflate(LayoutInflater.java:545)
                                                 	at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
                                                 	at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:775)
                                                 	at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:197)
                                                 	at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:303)
                                                 	at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:284)
                                                 	at android.app.Activity.performCreate(Activity.java:8891)
                                                 	at android.app.Activity.performCreate(Activity.java:8856)
                                                 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1468)
                                                 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3953)
                                                 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4124)
                                                 	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
                                                 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
                                                 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:99)
                                                 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2572)
                                                 	at android.os.Handler.dispatchMessage(Handler.java:106)
                                                 	at android.os.Looper.loopOnce(Looper.java:224)
                                                 	at android.os.Looper.loop(Looper.java:318)
                                                 	at android.app.ActivityThread.main(ActivityThread.java:8653)
2024-08-05 18:45:03.468 AndroidRuntime        E  	at java.lang.reflect.Method.invoke(Native Method)
                                                 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:561)
                                                 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
                                                 Caused by: java.lang.reflect.InvocationTargetException
                                                 	at java.lang.reflect.Constructor.newInstance0(Native Method)
                                                 	at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
                                                 	at androidx.coordinatorlayout.widget.CoordinatorLayout.parseBehavior(CoordinatorLayout.java:647)
                                                 	... 32 more
                                                 Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 3: TypedValue{t=0x2/d=0x7f04013f a=15}, 
                                                 	at android.content.res.TypedArray.getColorStateList(TypedArray.java:603)
                                                 	at com.google.android.material.resources.MaterialResources.getColorStateList(MaterialResources.java:81)
                                                 	at com.google.android.material.bottomsheet.BottomSheetBehavior.<init>(BottomSheetBehavior.java:353)

使用的GoogleMaterial版本

makefile 复制代码
com.google.android.material:material:1.10.0

布局文件代码:

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/settings_standard_bottom_sheet"
            style="@style/Widget.Material3.BottomSheet"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_height="match_parent"
            android:background="@color/black"
            app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

            <com.google.android.material.bottomsheet.BottomSheetDragHandleView
                android:layout_gravity="center_horizontal"
                android:src="@drawable/top_bottom_arrow"
                android:id="@+id/drag_handle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_20"
                android:paddingVertical="@dimen/dp_20"
                android:text="@string/about_ChatBird"
                android:textSize="@dimen/sp_22"
                android:textStyle="bold" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_20"
                android:layout_marginTop="@dimen/dp_60"
                android:paddingVertical="@dimen/dp_20"
                android:text="@string/account_management"
                android:textSize="@dimen/sp_22" />
        </LinearLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

代码是从material design官方copy过来的,肯定不会有问题

material-components-android/docs/components/BottomSheet.md at master · material-components/material-components-android (github.com)

原因分析

看报错内容,首先就是 CoordinatorLayout.parseBehavior,看源码

ini 复制代码
static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {
        if (TextUtils.isEmpty(name)) {
            return null;
        }

        final String fullName;
        if (name.startsWith(".")) {
            // Relative to the app package. Prepend the app package name.
            fullName = context.getPackageName() + name;
        } else if (name.indexOf('.') >= 0) {
            // Fully qualified package name.
            fullName = name;
        } else {
            // Assume stock behavior in this package (if we have one)
            fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)
                    ? (WIDGET_PACKAGE_NAME + '.' + name)
                    : name;
        }

        try {
            Map<String, Constructor<Behavior>> constructors = sConstructors.get();
            if (constructors == null) {
                constructors = new HashMap<>();
                sConstructors.set(constructors);
            }
            Constructor<Behavior> c = constructors.get(fullName);
            if (c == null) {
                final Class<Behavior> clazz =
                        (Class<Behavior>) Class.forName(fullName, false, context.getClassLoader());
                c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
                c.setAccessible(true);
                constructors.put(fullName, c);
            }
            return c.newInstance(context, attrs);
        } catch (Exception e) {
            throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);
        }
    }

根据报错内容,可以确定是 c.newInstance 实例化 BottomSheetBehavior 时抛异常,接着我们看下BottomSheetBehavior的构造函数,报错的方法在于 TypedArray.getColorStateList ,而BottomSheetBehavior中对应的调用是在MaterialResources.getColorStateList

ini 复制代码
this.peekHeightGestureInsetBuffer = context.getResources().getDimensionPixelSize(dimen.mtrl_min_touch_target_size);
        TypedArray a = context.obtainStyledAttributes(attrs, styleable.BottomSheetBehavior_Layout);
        if (a.hasValue(styleable.BottomSheetBehavior_Layout_backgroundTint)) {
            this.backgroundTint = MaterialResources.getColorStateList(context, a, styleable.BottomSheetBehavior_Layout_backgroundTint);
        }

从报错的源头java.lang.UnsupportedOperationException: Failed to resolve attribute at index 3: TypedValue{t=0x2/d=0x7f04013f a=5}这一段可以初步分析出,原因在于BottomSheetBehavior 构造函数在从主题或XML属性集中获取某个自定义属性的值时,解析失败,而这个属性的id,就是 0x7f04013f那么我们就可以从这个属性入手,找到对应的属性名称,再给它赋值。

如何找到这个属性id对应的名称,以及对应的定义源文件呢?

可以参考这篇文章:Android R文件详细介绍、瘦身方案和原理 - 掘金 (juejin.cn)

关键在于 app\build\intermediates\compile_and_runtime_not_namespaced_r_class_jar\debug\processReleaseResources 下面的R.jar。使用jadx反编译,查看R文件定义的属性集合,找到0x7f04013f对应的属性名称

可以看到 colorSurface 这个属性就是我们要找的。

解决方案

接下来我们要在Application或者Activity的主题中,加入colorSurface这个属性,并在colors.xml中定义其内容。

styles.xml

xml 复制代码
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        ......
        <!--  Material Components 默认背景色   -->
        <item name="colorSurface">@color/colorSurface</item>
        ......
</style>

colors.xml

xml 复制代码
<resources>
	......
	<color name="colorSurface">#ffffff</color>
	......
</resources>

问题解决。

相关推荐
松仔log10 小时前
Java中级——组合和继承
android·java·开发语言
我命由我1234514 小时前
Jetpack Compose - MaterialExpressiveTheme 与 MaterialTheme、ColorScheme
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
lilian23315 小时前
Harmony os 技术实战|拼豆制图06:收藏 ID、生成记录与重启恢复怎么不打架
android·java·数据库·harmonyos
2601_9557596215 小时前
ClaudeAPI成本中心与业务标签设计指南
android·java·数据库
余衫马15 小时前
2026最新版!Android Studio 极速安装与配置指南
android·ide·android studio
AFinalStone15 小时前
Android 7系统异常问题排查(五)Framework层(下)—System Server崩溃
android·tombstone·系统异常
AFinalStone15 小时前
Android 7系统异常问题排查(八)系统追踪—Trace机制与性能诊断
android·系统异常
极客猴子19 小时前
Android录音转写频繁卡顿?多款APP长时间会议场景稳定性实测
android·人工智能·智能手机·飞书
Kapaseker19 小时前
Boolean 变量到底该怎么命名?
android·kotlin
AFinalStone19 小时前
Android 7系统异常问题排查(六)应用异常(上)—ANR机制全解
android·系统异常