Android 10: "Probable deadlock detected due to WebView API being called on incorrect thread while the UI thread is blocked"

Android 10: "Probable deadlock detected due to WebView API being called on incorrect thread while the UI thread is blocked"

我的应用由 Fragments 和全屏 WebView 组成。当用户单击 WebView 中的 link 时,会打开带有新 WebView[=33= 的新 Fragment ] 同URL。在打开新 Fragment 之前,我关闭软键盘以防万一。我很快打开新页面。所有操作都在主线程上执行。

根据 Crashlytics,该问题仅出现在 Android 10(所有 Pixel 系列设备和其他配备 10 的设备)上。 在 Android 10 之前的设备上一切正常。我可以打开很多 Fragments。但是在 Android 10 台设备上,这种情况会导致致命异常(随机快速尝试打开新页面 2-3 次后):

E/AndroidRuntime: FATAL EXCEPTION: pool-1-thread-1
Process: <myapp>, PID: 12487
java.lang.RuntimeException: Probable deadlock detected due to WebView API being called on incorrect thread while the UI thread is blocked.
    at Yp.a(PG:13)
    at com.android.webview.chromium.WebViewChromium.onCheckIsTextEditor(PG:4)
    at android.webkit.WebView.onCheckIsTextEditor(WebView.java:3035)
    at android.view.inputmethod.InputMethodManager.checkFocusNoStartInput(InputMethodManager.java:1901)
    at android.view.inputmethod.InputMethodManager.checkFocus(InputMethodManager.java:1863)
    at android.view.inputmethod.InputMethodManager.hideSoftInputFromWindow(InputMethodManager.java:1506)
    at android.view.inputmethod.InputMethodManager.hideSoftInputFromWindow(InputMethodManager.java:1475)
    at <myapp>.Utils.hideKeyboard(Utils.java:175)
    at <myapp>.openNewPage(Pager.java:210)
    ...
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:919)
 Caused by: java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask.get(FutureTask.java:206)
    at Yp.a(PG:11)

我尝试使用所有可用版本的 Android System WebView(稳定版、测试版、开发版、金丝雀版),但无济于事。
有人可以帮帮我吗?

更新:
如果我注释隐藏软键盘的代码,那么一切正常。

我找到了解决方案,但不确定它是否正确。如果有人知道这次崩溃的原因或更优雅的解决方案,我将不胜感激。

解决方案:将hideSoftInputFromWindow()包裹在View.post()中:

public static void hideKeyboard(@NotNull Context context, @NotNull View view, int flags) {
  view.post(() ->
    ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE))
      .hideSoftInputFromWindow(view.getWindowToken(), flags));
}

这不是解决方案,只是说明问题。

首先,您说的是"All operations perform on the main thread.",但这是错误的。 堆栈树表明它在工作线程中。

而且从源码上也可以证实。 WebView's blocking task.

其次,代码在 Android Q 中更改,从这个版本开始 checks view is text editor

第三,您 post 使用 View.post() 完成一项任务。在UI个线程中,在WebView中处理不同(即不需要等待和阻塞)

综上所述,InputMethodManager 在非UI 线程中启动了一个任务(WebView.onCheckIsTextEditor()),而WebView 想在UI 线程中执行它,但它没有得到超时结果(4 秒)。

所以是因为你在UI线程

中的工作量太大了

我认为这不是解决这个问题的正确方法,但它应该通过扩展 WebView class 和覆盖 onCheckIsTextEditor() 方法来解决这个问题:

@Override
public boolean onCheckIsTextEditor() {
    try {
        return super.onCheckIsTextEditor();
    } catch (Throwable th) {
        // Probable deadlock detected due to WebView API being called on incorrect thread while the UI thread is blocked.
        return true; // or return false in your scenario.
    }
}