通过 WebView.loadURL() 指定不存在的 URL 时,WebViewClient.onPageStarted( ) 被调用两次

发布于 2024-10-27 10:22:10 字数 1150 浏览 6 评论 0原文

这是我的代码

public class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);


    WebView webView = (WebView)findViewById(R.id.webView);

    // Assign webclient.
    webView.setWebViewClient(new WebViewClient( ) {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            Log.d("TAG", url);
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Log.d("TAG", "failed: " + failingUrl + ", error code: " + errorCode + " [" + description + "]");
        }
    });


    webView.loadUrl("http://m.vooglemoogle.com" );
}



}

结果如下日志:

03-29 13:40:27.005: DEBUG/TAG(10948): http://m.vooglemoogle.com/
03-29 13:40:27.599: DEBUG/TAG(10948): failed: http://m.vooglemoogle.com/, error code: -2[The URL could not be found.]
03-29 13:40:27.607: DEBUG/TAG(10948): http://m.vooglemoogle.com/

注意对 onPageStarted( ) 的另一个调用...有谁知道这背后的原因吗? 干杯!

Here is my code

public class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);


    WebView webView = (WebView)findViewById(R.id.webView);

    // Assign webclient.
    webView.setWebViewClient(new WebViewClient( ) {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            Log.d("TAG", url);
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Log.d("TAG", "failed: " + failingUrl + ", error code: " + errorCode + " [" + description + "]");
        }
    });


    webView.loadUrl("http://m.vooglemoogle.com" );
}



}

Results in the following log:

03-29 13:40:27.005: DEBUG/TAG(10948): http://m.vooglemoogle.com/
03-29 13:40:27.599: DEBUG/TAG(10948): failed: http://m.vooglemoogle.com/, error code: -2[The URL could not be found.]
03-29 13:40:27.607: DEBUG/TAG(10948): http://m.vooglemoogle.com/

Note another call to onPageStarted( ) ... Does anyone know the reason behind this?
cheers!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凡间太子 2024-11-03 10:22:10

我在使用 API 7 的 AVD 上测试我的应用程序时遇到了同样的问题(不确定这是否相关,但无论如何)。

我注意到回调的确切顺序如下:

onPageStarted()     // url = non-existing url
onLoadResource()    // url = non-existing url
onReceivedError()   // url = non-existing url

onPageStarted()     // url = non-existing url
onLoadResource()    // url = file://android_assed/webkit/android-weberror.png
onPageFinished()    // url = non-existing url

所以我猜测 Android“网页不可用”页面的加载正在触发第二个 onPageStarted 调用。

I encountered the same problem while testing my app on an AVD with API 7 (not sure if this is relevant but in any case).

I noticed that the exact sequence of callbacks is the following:

onPageStarted()     // url = non-existing url
onLoadResource()    // url = non-existing url
onReceivedError()   // url = non-existing url

onPageStarted()     // url = non-existing url
onLoadResource()    // url = file://android_assed/webkit/android-weberror.png
onPageFinished()    // url = non-existing url

So I guess the loading of the Android "Web page not available" page is triggering the second onPageStarted call.

狠疯拽 2024-11-03 10:22:10

我也曾为此苦苦挣扎,但我想我已经解决了。基本上,我设置了一个错误标志,以防止客户端处理更多回调。当我调用活动中的方法以再次尝试加载时,该标志会重置。这是我创建的要点中的一些示例代码 https://gist.github.com/museofwater/6373048

public class AsyncMultiplayerSetupActivity extends Activity {

    private static final String TAG = AsyncMultiplayerSetupActivity.class.getName();
    public static final String UTF_8 = "UTF-8";

    private WebView wvSignin;
    private String url = "http://localhost:9000/signin";
    private ProgressDialog progressLoadUrl;
    private SigninWebViewClient webViewClient;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        registerUser(url);
    }

    private void registerUser(String url) {
        webViewClient = new SigninWebViewClient(getResources().getInteger(R.integer.timeout));
        setContentView(R.layout.setup);
        wvSignin = (WebView)findViewById(R.id.wvSignin);
        wvSignin.getSettings().setJavaScriptEnabled(true);
        wvSignin.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        wvSignin.setWebViewClient(webViewClient);
        loadUrl(url);
    }

    private void loadUrl(String url) {
        if (!NetworkUtil.checkNetwork(this)) {
            setSigninFailureResult();
        }
        // Show progress
        progressLoadUrl =
                ProgressDialog.show(this, getString(R.string.CONNECTING_TITLE),
                        getString(R.string.CONNECTING_MSG));
        webViewClient.prepareToLoadUrl();
        wvSignin.loadUrl(url);
    }

    private void setSigninFailureResult() {
        setResult(getResources().getInteger(R.integer.RESPONSE_FAILED_CODE));
        finish();
    }

    private void setSigninResult() {    
        setResult(getResources().getInteger(R.integer.RESPONSE_OK_CODE));
    }

    private class SigninWebViewClient extends WebViewClient {
        /**
         * Timeout for page load in seconds
         */
        private int timeout;
        private String urlLoading;

        boolean pageLoaded = false;

        // Flag to instruct the client to ignore callbacks after an error
        boolean hasError = false;

        private Handler timeoutHandler;
        private AlertDialog alertDialog;

        private SigninWebViewClient(int timeout) {
            this.timeout = timeout;
            timeoutHandler = new Handler();
        }

        // Called by activity before requesting load of a url
        private void prepareToLoadUrl() {
           this.hasError = false;
           this.pageLoaded = true;
           this.urlLoading = null;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            if (hasError) {
                return;
            }
            urlLoading = url;
            // timeout has expired if this flag is still set when the message is handled
            pageLoaded = false;
            Runnable run = new Runnable() {
                public void run() {
                    // Do nothing if we already have an error
                    if (hasError) {
                        return;
                    }

                    // Dismiss any current alerts and progress
                    dismissProgress();
                    dismissErrorAlert();
                    if (!pageLoaded) {
                        showTimeoutAlert();
                    }
                }
            };
            timeoutHandler.postDelayed(run, this.timeout*1000);
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            // Ignore future callbacks because the page load has failed
            hasError = true;
            dismissProgress();
            showServerErrorAlert();
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            if (hasError) {
                return;
            }
            pageLoaded = true;
            dismissProgress();
            dismissErrorAlert();
            urlLoading = null;

            // Do whatever processing you need to on page load here
         }

        private void showTimeoutAlert() {
            showErrorAlert(R.string.TIMEOUT_TITLE, R.string.TIMEOUT_MSG);
        }

        private void showServerErrorAlert() {
            showErrorAlert(R.string.SERVER_ERROR_TITLE,R.string.SERVER_ERROR_MSG);
        }

        private void showErrorAlert(int titleResource, int messageResource) {
            AlertDialog.Builder builder = new AlertDialog.Builder(AsyncMultiplayerSetupActivity.this);
            // Add the buttons
            builder.setTitle(titleResource)
                    .setMessage(messageResource)
                    .setPositiveButton(R.string.RETRY, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            // Try to load url again
                            loadUrl(urlLoading);
                            dialog.dismiss();
                        }
                    });
            builder.setNegativeButton(R.string.CANCEL, new DialogInterface.OnClickListener() {
                 public void onClick(DialogInterface dialog, int id) {
                     // User cancelled the dialog
                     setSigninFailureResult();
                     dialog.cancel();
                }
            });

            // Create the AlertDialog
            alertDialog = builder.create();
            alertDialog.show();
        }

        private void dismissProgress() {
            if (progressLoadUrl != null && progressLoadUrl.isShowing()) {
                progressLoadUrl.dismiss();
            }
        }

        private void dismissErrorAlert() {
            if (alertDialog != null && alertDialog.isShowing()) {
                alertDialog.dismiss();
            }
        }
    }
}

I struggled with this as well, but I think I've worked around it. Basically I set a flag on error to keep the client from processing any more callbacks. The flag gets reset when I call a method in the activity to try the load again. Here is some sample code from a gist I created https://gist.github.com/museofwater/6373048

public class AsyncMultiplayerSetupActivity extends Activity {

    private static final String TAG = AsyncMultiplayerSetupActivity.class.getName();
    public static final String UTF_8 = "UTF-8";

    private WebView wvSignin;
    private String url = "http://localhost:9000/signin";
    private ProgressDialog progressLoadUrl;
    private SigninWebViewClient webViewClient;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        registerUser(url);
    }

    private void registerUser(String url) {
        webViewClient = new SigninWebViewClient(getResources().getInteger(R.integer.timeout));
        setContentView(R.layout.setup);
        wvSignin = (WebView)findViewById(R.id.wvSignin);
        wvSignin.getSettings().setJavaScriptEnabled(true);
        wvSignin.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        wvSignin.setWebViewClient(webViewClient);
        loadUrl(url);
    }

    private void loadUrl(String url) {
        if (!NetworkUtil.checkNetwork(this)) {
            setSigninFailureResult();
        }
        // Show progress
        progressLoadUrl =
                ProgressDialog.show(this, getString(R.string.CONNECTING_TITLE),
                        getString(R.string.CONNECTING_MSG));
        webViewClient.prepareToLoadUrl();
        wvSignin.loadUrl(url);
    }

    private void setSigninFailureResult() {
        setResult(getResources().getInteger(R.integer.RESPONSE_FAILED_CODE));
        finish();
    }

    private void setSigninResult() {    
        setResult(getResources().getInteger(R.integer.RESPONSE_OK_CODE));
    }

    private class SigninWebViewClient extends WebViewClient {
        /**
         * Timeout for page load in seconds
         */
        private int timeout;
        private String urlLoading;

        boolean pageLoaded = false;

        // Flag to instruct the client to ignore callbacks after an error
        boolean hasError = false;

        private Handler timeoutHandler;
        private AlertDialog alertDialog;

        private SigninWebViewClient(int timeout) {
            this.timeout = timeout;
            timeoutHandler = new Handler();
        }

        // Called by activity before requesting load of a url
        private void prepareToLoadUrl() {
           this.hasError = false;
           this.pageLoaded = true;
           this.urlLoading = null;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            if (hasError) {
                return;
            }
            urlLoading = url;
            // timeout has expired if this flag is still set when the message is handled
            pageLoaded = false;
            Runnable run = new Runnable() {
                public void run() {
                    // Do nothing if we already have an error
                    if (hasError) {
                        return;
                    }

                    // Dismiss any current alerts and progress
                    dismissProgress();
                    dismissErrorAlert();
                    if (!pageLoaded) {
                        showTimeoutAlert();
                    }
                }
            };
            timeoutHandler.postDelayed(run, this.timeout*1000);
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            // Ignore future callbacks because the page load has failed
            hasError = true;
            dismissProgress();
            showServerErrorAlert();
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            if (hasError) {
                return;
            }
            pageLoaded = true;
            dismissProgress();
            dismissErrorAlert();
            urlLoading = null;

            // Do whatever processing you need to on page load here
         }

        private void showTimeoutAlert() {
            showErrorAlert(R.string.TIMEOUT_TITLE, R.string.TIMEOUT_MSG);
        }

        private void showServerErrorAlert() {
            showErrorAlert(R.string.SERVER_ERROR_TITLE,R.string.SERVER_ERROR_MSG);
        }

        private void showErrorAlert(int titleResource, int messageResource) {
            AlertDialog.Builder builder = new AlertDialog.Builder(AsyncMultiplayerSetupActivity.this);
            // Add the buttons
            builder.setTitle(titleResource)
                    .setMessage(messageResource)
                    .setPositiveButton(R.string.RETRY, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            // Try to load url again
                            loadUrl(urlLoading);
                            dialog.dismiss();
                        }
                    });
            builder.setNegativeButton(R.string.CANCEL, new DialogInterface.OnClickListener() {
                 public void onClick(DialogInterface dialog, int id) {
                     // User cancelled the dialog
                     setSigninFailureResult();
                     dialog.cancel();
                }
            });

            // Create the AlertDialog
            alertDialog = builder.create();
            alertDialog.show();
        }

        private void dismissProgress() {
            if (progressLoadUrl != null && progressLoadUrl.isShowing()) {
                progressLoadUrl.dismiss();
            }
        }

        private void dismissErrorAlert() {
            if (alertDialog != null && alertDialog.isShowing()) {
                alertDialog.dismiss();
            }
        }
    }
}
彩扇题诗 2024-11-03 10:22:10

在android API中,你可以找到注释:

通知主机应用程序页面已开始加载。这
每个主框架加载都会调用一次方法,因此带有 iframe 的页面
或框架集将为主框架调用一次 onPageStarted 。这
也意味着 onPageStarted 不会被调用,当内容
嵌入的框架发生变化,即单击目标为
iframe。

这表明它可能是由网页中的“iframe”引起的。

In the android API, you can find the note:

Notify the host application that a page has started loading. This
method is called once for each main frame load so a page with iframes
or framesets will call onPageStarted one time for the main frame. This
also means that onPageStarted will not be called when the contents of
an embedded frame changes, i.e. clicking a link whose target is an
iframe.

Which suggests that it could be caused by "iframes" in the web page.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文