android.view.InflateException:解析类android.webkit.WebView时出错

152

在 Lollipop(API 22)中,每当我在应用程序中显示一个 webview 时,应用程序就会崩溃。我的 Android 开发者控制台中有多个与此事件相关的崩溃。

不需要说它在 Android 4、6 和 7 上都可以正常工作。

阅读堆栈跟踪(发布在本帖子的末尾),有些事情让我感到困扰。

Caused by: android.content.res.Resources$NotFoundException: String resource ID #0x2040003

我在生成的R.java文件中进行了搜索,但没有运气,很明显因为ID不存在,但值得一试。

通过Google搜索发现问题似乎与Lollipop如何处理WebView有关。我基于GDC崩溃报告中找到的设备启动了一个基于Lollipop的新AVD,并且可以重现这个问题。


完整堆栈跟踪:

android.view.InflateException: Binary XML file line #7: Error inflating class android.webkit.WebView
                  at android.view.LayoutInflater.createView(LayoutInflater.java:633)
                  at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:55)
                  at android.view.LayoutInflater.onCreateView(LayoutInflater.java:682)
                  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:741)
                  at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
                  at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
                  at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
                  at it.artecoop.ibreviary.WebViewFragment.onCreateView(WebViewFragment.java:67)
                  at android.support.v4.app.Fragment.performCreateView(Fragment.java:2087)
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1113)
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1295)
                  at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)
                  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1682)
                  at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:541)
                  at android.os.Handler.handleCallback(Handler.java:739)
                  at android.os.Handler.dispatchMessage(Handler.java:95)
                  at android.os.Looper.loop(Looper.java:135)
                  at android.app.ActivityThread.main(ActivityThread.java:5254)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at java.lang.reflect.Method.invoke(Method.java:372)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
               Caused by: java.lang.reflect.InvocationTargetException
                  at java.lang.reflect.Constructor.newInstance(Native Method)
                  at java.lang.reflect.Constructor.newInstance(Constructor.java:288)
                  at android.view.LayoutInflater.createView(LayoutInflater.java:607)
                  at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:55) 
                  at android.view.LayoutInflater.onCreateView(LayoutInflater.java:682) 
                  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:741) 
                  at android.view.LayoutInflater.rInflate(LayoutInflater.java:806) 
                  at android.view.LayoutInflater.inflate(LayoutInflater.java:504) 
                  at android.view.LayoutInflater.inflate(LayoutInflater.java:414) 
                  at it.artecoop.ibreviary.WebViewFragment.onCreateView(WebViewFragment.java:67) 
                  at android.support.v4.app.Fragment.performCreateView(Fragment.java:2087) 
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1113) 
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1295) 
                  at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801) 
                  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1682) 
                  at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:541) 
                  at android.os.Handler.handleCallback(Handler.java:739) 
                  at android.os.Handler.dispatchMessage(Handler.java:95) 
                  at android.os.Looper.loop(Looper.java:135) 
                  at android.app.ActivityThread.main(ActivityThread.java:5254) 
                  at java.lang.reflect.Method.invoke(Native Method) 
                  at java.lang.reflect.Method.invoke(Method.java:372) 
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 
               Caused by: android.content.res.Resources$NotFoundException: String resource ID #0x2040003
                  at android.content.res.Resources.getText(Resources.java:299)
                  at android.content.res.Resources.getString(Resources.java:385)
                  at com.android.org.chromium.content.browser.ContentViewCore.setContainerView(ContentViewCore.java:684)
                  at com.android.org.chromium.content.browser.ContentViewCore.initialize(ContentViewCore.java:608)
                  at com.android.org.chromium.android_webview.AwContents.createAndInitializeContentViewCore(AwContents.java:631)
                  at com.android.org.chromium.android_webview.AwContents.setNewAwContents(AwContents.java:780)
                  at com.android.org.chromium.android_webview.AwContents.<init>(AwContents.java:619)
                  at com.android.org.chromium.android_webview.AwContents.<init>(AwContents.java:556)
                  at com.android.webview.chromium.WebViewChromium.initForReal(WebViewChromium.java:311)
                  at com.android.webview.chromium.WebViewChromium.access$100(WebViewChromium.java:96)
                  at com.android.webview.chromium.WebViewChromium$1.run(WebViewChromium.java:263)
                  at com.android.webview.chromium.WebViewChromium$WebViewChromiumRunQueue.drainQueue(WebViewChromium.java:123)
                  at com.android.webview.chromium.WebViewChromium$WebViewChromiumRunQueue$1.run(WebViewChromium.java:110)
                  at com.android.org.chromium.base.ThreadUtils.runOnUiThread(ThreadUtils.java:144)
                  at com.android.webview.chromium.WebViewChromium$WebViewChromiumRunQueue.addTask(WebViewChromium.java:107)
                  at com.android.webview.chromium.WebViewChromium.init(WebViewChromium.java:260)
                  at android.webkit.WebView.<init>(WebView.java:554)
                  at android.webkit.WebView.<init>(WebView.java:489)
                  at android.webkit.WebView.<init>(WebView.java:472)
                  at android.webkit.WebView.<init>(WebView.java:459)
                  at java.lang.reflect.Constructor.newInstance(Native Method) 
                  at java.lang.reflect.Constructor.newInstance(Constructor.java:288) 
                  at android.view.LayoutInflater.createView(LayoutInflater.java:607) 
                  at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:55) 
                  at android.view.LayoutInflater.onCreateView(LayoutInflater.java:682) 
                  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:741) 
                  at android.view.LayoutInflater.rInflate(LayoutInflater.java:806) 
                  at android.view.LayoutInflater.inflate(LayoutInflater.java:504) 
                  at android.view.LayoutInflater.inflate(LayoutInflater.java:414) 
                  at it.artecoop.ibreviary.WebViewFragment.onCreateView(WebViewFragment.java:67) 
                  at android.support.v4.app.Fragment.performCreateView(Fragment.java:2087) 
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1113) 
                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1295) 
                  at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801) 
                  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1682) 
                  at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:541) 
                  at android.os.Handler.handleCallback(Handler.java:739) 
                  at android.os.Handler.dispatchMessage(Handler.java:95) 
                  at android.os.Looper.loop(Looper.java:135) 
                  at android.app.ActivityThread.main(ActivityThread.java:5254) 
                  at java.lang.reflect.Method.invoke(Native Method) 
                  at java.lang.reflect.Method.invoke(Method.java:372) 
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698

这似乎是一个系统WebView问题。我不知道模拟器是否会更新它。你试过在硬件上吗? - CommonsWare
@commonsware 我现在没有任何安装Lollipop的设备。但是崩溃报告显示了多个条目。 - Valerio
21
这个问题最初出现在2016年,但在2019年末又再次浮现。如果您是通过网络搜索进入此页面,请确保选择适用于您的答案。 - WSBT
我没有API 21物理设备。我尝试在Genymotion和Android模拟器上运行具有API 21的应用程序,但它会崩溃!这里有人可以告诉我它是否适用于物理设备!现在我的应用程序处于风险状态! - Sumit Shukla
对我来说,Google Play 在运行 Android 5.0 的华为 P8 Lite 上报告了问题,但在运行 Android 6.0.1 的三星 Note 4 或运行 Android 4.4.2 的三星 Note 8 平板电脑上没有出现这个问题。 - FractalBob
最近我在Android 10上遇到了崩溃问题,主要是三星用户。有人也遇到了同样的麻烦吗? - neobie
21个回答

193
如果你使用的是androidx.appcompat:appcompat:1.1.0,请尝试使用androidx.appcompat:appcompat:1.0.2代替。似乎1.1.0在Android 5.1.1中没有修复WebView的错误。 2020年2月更新:回退到1.0.2对许多人(包括我的应用程序)都不再适用,但使用当前版本的androidx.appcompat:appcompat:1.2.0-alpha02可以修复崩溃。(我在一台运行Android 5.0的华为P8 Lite上,在Google的自动化“预启动报告”测试期间看到了这个问题。) 2020年6月更新:现在有比2020年2月更新中提到的更新版本可用,您可以在此处查看当前可用的版本:https://developer.android.com/jetpack/androidx/releases/appcompat

3
有没有修复这个问题但同时保留1.1.0版本的bug修复?我们依赖一些在1.0.2中不存在的东西,貌似某些1.1.0的alpha或beta版本没有这个bug。 - Roudi
3
没问题,谢谢!“是的,清理了一下就好了,谢谢!我正在使用beta01版本,一切似乎都很好。我会继续使用它,因为使用1.1.0没有明显的好处。” - Roudi
11
这个回归问题存在一个相关问题:https://issuetracker.google.com/issues/141132133 - Brais Gabin
3
至今,降级无法解决问题,对我而言,这个 https://issuetracker.google.com/issues/141132133 的解决方案有效:"或许最简单的解决方法是强制 Gradle 将版本设置为 1.1.0-rc01。将以下代码添加到你的 gradle 文件中。configurations.all { resolutionStrategy { force 'androidx.appcompat:appcompat:1.1.0-rc01' } }" - Talu
3
将实现升级至'androidx.appcompat:appcompat:1.2.0-beta01解决了问题,但它对6.0及以上版本是否有任何副作用? - Girish
显示剩余10条评论

53
如果您正在使用androidx.appcompat:appcompat:1.1.0,并且不想降级到androidx.appcompat:appcompat:1.0.2或升级到androidx.appcompat:appcompat:1.2.0-alpha03,则还有另一种解决方案,详见Google问题跟踪器上此评论

我注意到调用applyOverrideConfiguration后,Context.getAssets()Context.getResources().getAssets()返回的不是同一个AssetManager对象。从Context.getAssets()返回的AssetManager无法访问其他包(包括系统WebView包)中的资源,导致WebView崩溃。如果我重写Context.getAssets()以返回getResources().getAssets(),问题就解决了。

根据该评论,您可以在WebView的Activity中覆盖getAssets()方法,使其返回getResources().getAssets()以解决此问题。
Java
@Override
public AssetManager getAssets() {
    return getResources().getAssets();
}

Kotlin

override fun getAssets(): AssetManager {
    return resources.assets
}

如果这是真的,那么与 AssetManager 和 webview 本身无关的 appCompact 发布将如何解决这个问题? - Sinapse
看了一下这个变更列表,似乎一些WebView版本在AppCompat库内部的applyOverrideConfiguration调用方面存在问题。 - Prawira

46

警告:这种解决方法可能会破坏一些东西,详见注释。

如果您想从XML布局中填充WebView,可以将其包装在一个漂亮的小子类中(基于ikostet的答案):

public class LollipopFixedWebView extends WebView {
    public LollipopFixedWebView(Context context) {
        super(getFixedContext(context));
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs) {
        super(getFixedContext(context), attrs);
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(getFixedContext(context), attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(getFixedContext(context), attrs, defStyleAttr, defStyleRes);
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
        super(getFixedContext(context), attrs, defStyleAttr, privateBrowsing);
    }

    public static Context getFixedContext(Context context) {
        return context.createConfigurationContext(new Configuration());
    }
}

编辑:现在使用 Kotlin 更加舒适

class LollipopFixedWebView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0
) : WebView(context.createConfigurationContext(Configuration()), attrs, defStyleAttr, defStyleRes)

1
我遇到了同样的问题,并使用了这个解决方案来修复它,谢谢。 - itsa04g9
2
依然存在一个问题在2019年,它能够运行,但是我不知道为什么或者如何工作,如果能解释清楚就更好了。同时,我收到了一个警告:“public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)”构造器中的“Is never used”。 - David
5
关于这个解决方法,需要提醒一句:使用空白的上下文实例化WebView可能会导致意想不到的副作用。例如,来自WebView的ActionModes(比如长按以高亮文本)可能不再起作用。 - Dmitry Brant
7
正如 @DmitryBrant 所说,实现这个功能时要非常小心,因为这会影响到一些东西,包括“下拉菜单”和“长按突出显示文本”! - user5507535
当单击输入框时,键盘不会显示,这是由于某种原因引起的。 - hrach
显示剩余8条评论

37

我的建议是仅在“原始配置”出现问题时,即仅在使用Android 5.0(棒棒糖)时使用自定义/新的 Configuration 。 @SpaceBizon 的代码在 Android 8.x 上运行良好,在 9 和 Q(当前测试版)上,每次选择/下拉操作都不会显示 AlertDialog 选择器,而是会导致内存泄漏...下面是修复了版本代码的 getFixedContext 方法。

public class LollipopFixedWebView extends WebView {

    public LollipopFixedWebView(Context context) {
        super(getFixedContext(context));
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs) {
        super(getFixedContext(context), attrs);
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(getFixedContext(context), attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(getFixedContext(context), attrs, defStyleAttr, defStyleRes);
    }

    private static Context getFixedContext(Context context) {
        if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23) // Android Lollipop 5.0 & 5.1
            return context.createConfigurationContext(new Configuration());
        return context;
    }
}

22

如果你正在使用androidx.appcompat:appcompat:1.1.0,请切换到androidx.appcompat:appcompat:1.0.2,或者如果你想使用DayNight主题,则在你的活动中覆盖 applyOverrideConfiguration 方法,如下所示。(注意:从暗色主题切换到亮色主题(反之亦然)需要重新启动应用程序。)

override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
        if (Build.VERSION.SDK_INT in 21..25 && (resources.configuration.uiMode ==  applicationContext.resources.configuration.uiMode)) {
                return
        }
        super.applyOverrideConfiguration(overrideConfiguration)
}

这个解决方法可行,但是应该是针对21..22而不是21..25吧?问题似乎在API 23+中没有出现。 - Dmitry Brant
5
这是导致崩溃的修订版- https://android.googlesource.com/platform/frameworks/support/+/26079d87c79a64829f036236353fac1dae4e0613%5E%21/#F2 。根据代码,在未安装Google Play商店且Android Webview版本<50的设备中,崩溃将发生在API 21..25。 - A R Mythili Saran
3
我在Java中找到的解决方法如下(抱歉格式较差,但这不是一个新答案而只是一个端口):@Override public void applyOverrideConfiguration(Configuration overrideConfiguration) { if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) { return; } super.applyOverrideConfiguration(overrideConfiguration); }该方法对我有效。 - Mike Hardy
@ARMythiliSaran,你为什么说这只发生在“未安装Google Play商店且Android Webview版本<50的设备上”? - andrei
@andrei 我已经在我拥有的物理设备(Android 5.1)上进行了验证。在具有Google Play商店的设备上,如果我更新Webview应用程序,则不会发生崩溃。在其他设备上,除非您自己安装最新的Webview apk,否则无法更新Webview。我能找到的最低版本的Webview apk是54版本,在该版本中也没有崩溃。因此,我决定在Webview<50时应用以上代码进入生产环境。迄今为止,我还没有收到任何与此相关的崩溃报告。看起来这个问题最近已经被解决了-https://issuetracker.google.com/issues/141351441。 - A R Mythili Saran
显示剩余3条评论

21
如果您不依赖DayNight主题切换(或其他UiMode事件),您可以在webview活动清单中添加 android:configChanges ="uiMode" ,以防止AppCompatDelegate更新资源配置,从而混乱webview膨胀。

这对我起作用。我需要 ConstraintLayout 1.1.3,它需要 appcompat 1.1.0,因此回退不是一个选项。 - Matt Robertson
降级到1.0.2对我没有任何影响,但这种方法有效。 - chrisbtoo
棒极了的解决方案! - bojan

17

尝试使用以下代码创建Webview:

mWebView = new WebView(getActivity().createConfigurationContext(new Configuration()));

我的 XML 文件呢? - Acauã Pitta
这解决了我的问题,而且没有降低任何库版本。 - Bugs Happen

11

再试一次以解决问题。应该在你的活动中覆盖这个方法:

    @Override
    public void applyOverrideConfiguration(final Configuration overrideConfiguration) {
        if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 25) {
            overrideConfiguration.uiMode &= ~Configuration.UI_MODE_NIGHT_MASK;
        }
        super.applyOverrideConfiguration(overrideConfiguration);
    }

6
以下代码将解决问题。请将其添加到您的Activity中:
@Override 
public AssetManager getAssets() {
    return getResources().getAssets(); 
}

6

我能够在模拟器中复现API 21的崩溃。

因此,我尝试按照文档所述将其添加到实现中:

dependencies {
    def appcompat_version = "1.1.0"

    implementation "androidx.appcompat:appcompat:$appcompat_version"
    // For loading and tinting drawables on older versions of the platform
    implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
}

添加appcompat-resources并没有解决这个问题。

也许将来的版本会解决,但我想提一下似乎有一个补充资源库可以解决这个问题。因此,在尝试使用新版本的appcompat修复此问题时,需要添加相同版本的appcompat-resources库。

回退到androidx.appcompat:appcompat:1.0.2作为解决方法确实解决了这个问题。


我无法将"androidx.appcompat:appcompat-resources:$appcompat_version"回滚到版本1.0.2。"ERROR: Failed to resolve: androidx.appcompat:appcompat-resources:1.0.2"。 - Murillo Comino
appcompat-resources在1.0.2中不可用。请查看我的更新答案。 - Manuel
非常感谢,它起作用了。我希望在未来的版本中解决这个问题。 - Murillo Comino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接