Случайное InflateException из-за ошибок ThemeEnforcement с использованием MaterialComponents. Как решить? - PullRequest
0 голосов
/ 08 января 2019

Потратив целый день на попытки выяснить это, я почти уверен, что это ошибка в библиотеке компонентов материалов. Вот соответствующие части моей конфигурации (удалены нерелевантные элементы):

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 голосов
/ 08 января 2019

Чтобы следить за комментариями: важно, чтобы вы использовали LayoutInflater, который был получен из Context, который использует правильную тему. Контекст приложения не будет удовлетворять этому требованию.

Хорошей новостью является то, что вам не нужно беспокоиться о вставке контекста в ваш адаптер. Это не сразу очевидно, но адаптер предоставляет все необходимое для получения правильного контекста.

Взгляните на onCreateViewHolder() скелет:

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

Все View экземпляры имеют метод getContext(), а параметр parent гарантированно будет ненулевым ... так что вы можете извлечь контекст из родительского элемента и использовать его для получения вашего 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();
    // ...
}
...