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.
}
}
我的应用由 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.
}
}