Android WebView onCreateWindow()偶发加载失败问题求助
我在WebChromeClient中通过onCreateWindow()方法,在Dialog内嵌的WebView中加载网页URL,多数场景下功能正常,但偶尔会出现WebView无法加载URL、弹窗空白的情况,同时收到以下日志错误:
D/bWebView: bPullDownRefresh:false isTopOverScrolled:false deltaY:4.0 downY:31.0
D/bWebView: bPullDownRefresh:false isTopOverScrolled:false deltaY:1.0 downY:68.0
D/bWebView: bPullDownRefresh:false isTopOverScrolled:false deltaY:0.0 downY:533.0
W/chromium: [WARNING:aw_contents.cc(1109)] Blocking popup window creation as an outstanding popup window is still pending.
W/cr_AwContents: Popup WebView bind failed: no pending content.
W/cr_AwContents: WebView.destroy() called while WebView is still attached to window.
我尝试调整过多种WebView设置,但问题依旧,当前实现代码如下:
@Override public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { final Dialog dialog = new Dialog(mContext); dialog.setContentView(R.layout.dialog_child_webview); dialog.setCancelable(true); final WebView newWebView = dialog.findViewById(R.id.wvChild); newWebView.getSettings().setJavaScriptEnabled(true); newWebView.getSettings().setSupportMultipleWindows(true); newWebView.getSettings().setDomStorageEnabled(true); newWebView.getSettings().setAllowFileAccess(true); newWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); newWebView.getSettings().setAppCacheMaxSize(Long.MAX_VALUE); newWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); newWebView.getSettings().setAppCacheEnabled(true); newWebView.getSettings().setAppCachePath(mContext.getApplicationContext().getCacheDir().getAbsolutePath()); dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(DialogInterface dlg, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: if (dialog != null && dialog.isShowing() && newWebView != null) { if (newWebView.canGoBack()) { newWebView.goBack(); } else { dialog.dismiss(); } return true; } break; } } return false; } }); ImageButton ivDialogClose = dialog.findViewById(R.id.icCloseDialog); ivDialogClose.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); final ProgressBar dlgProgressBar = dialog.findViewById(R.id.progressBar); newWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return super.shouldOverrideUrlLoading(view, url); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); dlgProgressBar.setVisibility(View.VISIBLE); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); dlgProgressBar.setVisibility(View.GONE); } }); dialog.show(); Window window = dialog.getWindow(); window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); newWebView.setWebChromeClient(new WebChromeClient() { @Override public void onCloseWindow(WebView window) { clearPortalCache(newWebView); if (dialog != null && dialog.isShowing()) dialog.dismiss(); } }); ((WebView.WebViewTransport) resultMsg.obj).setWebView(newWebView); resultMsg.sendToTarget(); return true; }
从日志错误分析,核心问题是弹窗请求未及时绑定导致创建被阻塞,以及WebView销毁时未正确从窗口分离,可通过以下几点修复:
1. 调整WebView绑定与Dialog显示的顺序
当前代码先显示Dialog再绑定WebView,会导致Chromium等待弹窗绑定的过程中触发“pending popup”错误。需先完成WebView与resultMsg的绑定,再显示Dialog:
// 先处理WebView绑定逻辑 ((WebView.WebViewTransport) resultMsg.obj).setWebView(newWebView); resultMsg.sendToTarget(); // 再显示Dialog并调整窗口参数 dialog.show(); Window window = dialog.getWindow(); window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
2. 正确处理Dialog关闭时的WebView销毁
日志中WebView.destroy() called while WebView is still attached to window说明WebView未从父布局分离就被销毁,需在Dialog的OnDismissListener中先移除WebView再销毁:
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { if (newWebView != null) { // 先从父布局移除WebView ((ViewGroup) newWebView.getParent()).removeView(newWebView); newWebView.destroy(); } } });
3. 防止重复弹窗的竞态问题
添加标志位,避免短时间内重复触发弹窗创建:
// 在类中添加成员变量 private boolean isPopupShowing = false; @Override public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { if (isPopupShowing) { return false; } isPopupShowing = true; final Dialog dialog = new Dialog(mContext); // ... 其他代码 dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { isPopupShowing = false; if (newWebView != null) { ((ViewGroup) newWebView.getParent()).removeView(newWebView); newWebView.destroy(); } } }); // ... 其他代码 }
4. 优化WebChromeClient的窗口关闭逻辑
确保onCloseWindow中同步更新弹窗状态标志位:
newWebView.setWebChromeClient(new WebChromeClient() { @Override public void onCloseWindow(WebView window) { isPopupShowing = false; clearPortalCache(newWebView); if (dialog != null && dialog.isShowing()) { dialog.dismiss(); } } });
5. 清理冗余的WebView设置
setAppCacheMaxSize(Long.MAX_VALUE)在API 18后已废弃,无需设置;shouldOverrideUrlLoading直接返回父类实现的代码可删除,简化逻辑。
内容的提问来源于stack exchange,提问作者Srikanth

