LayoutInflater.from 傳參不當引起的android.view.InflateException

1、復現

1.1. 場景

RecyclerView 裏面有個樓層使用 android.support.design.widget.TabLayout 作一個 Tab 切使用:android

1.2 問題代碼出處

RecyclerView.AdapterOnCreateViewHolder簡單返回一個ViewHolder:安全

return new ViewHolder(LayoutInflater
.from(applicationContext).inflate(R.layout.xx, parent, false))
複製代碼

這裏我使用的是ApplicationContext,由於我一直被教導不要持有activity的引用,so都是Context應該沒有什麼不一樣。bash

1.3 報錯

到樓層展現的時候報錯:app

android.view.InflateException: 
Binary XML file line #7: 
Error inflating class android.support.design.widget.TabLayout
複製代碼

2、查找問題代碼

2.1 XML 檢查

最早確定是檢查 xml 文件裏面的類路徑是否正確,檢查後發現沒問題。post

2.2 代碼分析

問題報錯解析 TabLayout 類的時出錯,打斷點,發如今該行代碼時崩潰(TabLayout代碼在不一樣版本里相關代碼位置會發生微調,本場景是design.28.0.0版本):ui

public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    ......
    TypedArray a = ThemeEnforcement.obtainStyledAttributes(...);
    ......
}
複製代碼

繼續深刻:this

public static TypedArray obtainStyledAttributes(Context context, AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @StyleableRes int... textAppearanceResIndices) {
    checkCompatibleTheme(context, set, defStyleAttr, defStyleRes);
    .....
}
複製代碼

繼續深刻:spa

private static void checkCompatibleTheme(Context context, AttributeSet set, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
    ......
    checkAppCompatTheme(context);
}
複製代碼

繼續深刻:code

public static void checkAppCompatTheme(Context context) {
    checkTheme(context, APPCOMPAT_CHECK_ATTRS, "Theme.AppCompat");
}
複製代碼

問題代碼找到component

private static void checkTheme(Context context, int[] themeAttributes, String themeName) {
    if (!isTheme(context, themeAttributes)) {
        throw new IllegalArgumentException("The style on this component requires your app theme to be " + themeName + " (or a descendant).");
    }
}
複製代碼

跟主題沒找到有關。

三. 分析

1. AppcompatActivity

咱們在使用繼承該 Activity 時必須使用 Theme.Appcompat 及其子類的主題,否則也會報這個錯誤。基本問題緣由能夠定位爲LayoutInflater沒有帶 theme 去解析。

2. Activity Context 與 Application Context 區別

Look at here:LayoutInflater.from參數Context傳Activity、Application區別

歸根結底是我傳入的是 ApplicationContext,解析時沒有帶 theme 致使崩潰。

4、總結

一直認爲 LayoutInflater.from() 傳入應用上下文一勞永逸且安全,在大多數場景下沒有問題,能夠成功解析,可是對於有 theme 要求的控件,仍是須要使用 activity 傳入解析。