You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 13:50:40