由于使用MaterialComponents发生ThemeEnforcement错误,偶尔发生InflateException。怎么解决?

时间:2019-01-07 21:54:37

标签: android android-theme material-components

花了一整天的时间试图弄清楚这一点之后,我几乎肯定这是材料组件库中的一个错误。这是我的配置的相关部分(删除了不相关的元素):

styles.xml:

<style name="MaterialAppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryVariant">@color/colorPrimary900</item>
    <item name="colorSecondary">@color/colorSecondary</item>
    <item name="colorSecondaryVariant">@color/colorSecondary900</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>

AndroidManifest:

<application
    android:name=".AndroidApplication"
    android:theme="@style/MaterialAppTheme">

MainActivity:

<activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:theme="@style/MaterialAppTheme">

依赖版本:

materialComponents: '1.1.0-alpha02',
constraintLayout  : '2.0.0-alpha3',
appCompat         : '1.1.0-alpha01'

我在向登录页面添加MaterialButton时没有问题。问题始于我的MainActivity的第一个列表片段。尝试以MaterialCardView作为每个项目的根目录显示回收者视图项目时,出现ThemeEnforcement错误。我尝试添加MaterialTextButton时也是如此。这是我的MaterialCardView xml声明的样子:

<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
                                               xmlns:card_view="http://schemas.android.com/apk/res-auto"
                                               xmlns:tools="http://schemas.android.com/tools"
                                               android:id="@+id/tripCard"
                                               style="@style/Widget.MaterialComponents.CardView"
                                               android:layout_width="match_parent"
                                               android:layout_height="wrap_content"
                                               android:layout_margin="8dp"
                                               card_view:cardBackgroundColor="@color/colorSurface"
                                               card_view:cardCornerRadius="@dimen/widget_corner_radius"
                                               card_view:cardElevation="@dimen/card_elevation">

在MaterialComponents库中进行断点处理时,我注意到它有时无法验证主题。以下是一些显示库失败代码的代码(在ThemeEnforcement.java中):

    if (enforceMaterialTheme) {
  TypedValue isMaterialTheme = new TypedValue();
  boolean resolvedValue =
      context.getTheme().resolveAttribute(R.attr.isMaterialTheme, isMaterialTheme, true);

  if (!resolvedValue
      || (isMaterialTheme.type == TypedValue.TYPE_INT_BOOLEAN && isMaterialTheme.data == 0)) {
    // If we were unable to resolve isMaterialTheme boolean attribute, or isMaterialTheme is
    // false, check for Material Theme color attributes
    checkMaterialTheme(context);
  }
}

public static void checkMaterialTheme(Context context) {
    checkTheme(context, MATERIAL_CHECK_ATTRS, MATERIAL_THEME_NAME);
}

private static final int[] MATERIAL_CHECK_ATTRS = {R.attr.colorPrimaryVariant};

据我所知,Theme Enforcer尝试解析isMaterialTheme属性(尽管在这种情况下它可能有时可以做到),然后继续进行操作并检查是否存在实质性主题颜色属性(检查colorPrimaryVariant)并再次失败(我也在应用程序主题中定义了它。)

如果有人有解决方案或任何建议,我将继续提交错误,将不胜感激!

1 个答案:

答案 0 :(得分:2)

要跟进评论:使用从正确主题的LayoutInflater中检索到的Context是很重要的。应用程序上下文将无法满足此要求。

好消息是您不必担心将上下文注入适配器。这不是立即显而易见的,但是适配器提供了获得正确上下文所需的一切。

看看onCreateViewHolder()骨架:

@NonNull 
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    // ...
}

所有View实例都有一个getContext()方法,并且保证parent参数为非null ...因此您可以从父级检索上下文并将其用于获取您的LayoutInflater:

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View itemView = inflater.inflate(R.layout.my_item_view, parent, false);
    return new MyViewHolder(itemView);
}

类似地,在ViewHolder内,您可以使用相同的技术来获取上下文对象。每个ViewHolder实例都有一个itemView字段,保证该字段为非空,因此您可以从中检索上下文。

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    Context context = holder.itemView.getContext();
    // ...
}