WebViewClient.onPageStarted () вызывается дважды при указании несуществующего URL через WebView.loadURL () - PullRequest
13 голосов
/ 29 марта 2011

Вот мой код

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 () ... Кто-нибудь знает причинуэтот?ура!

Ответы [ 3 ]

14 голосов
/ 09 декабря 2011

Я столкнулся с той же проблемой при тестировании моего приложения на AVD с API 7 (не уверен, что это актуально, но в любом случае).

Я заметил, что точная последовательность обратных вызовов следующая:

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.

2 голосов
/ 29 августа 2013

Я тоже боролся с этим, но, думаю, я обошел это. В основном я установил флаг на ошибку, чтобы клиент не обрабатывал больше обратных вызовов. Флаг сбрасывается, когда я вызываю метод в упражнении, чтобы снова попытаться загрузить. Вот пример кода из сущности, которую я создал 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();
            }
        }
    }
}
0 голосов
/ 08 ноября 2011

В Android API вы можете найти примечание:

Уведомить хост-приложение о том, что страница начала загружаться.Этот метод вызывается один раз для каждой загрузки основного кадра, поэтому страница с iframes или наборами кадров будет вызывать onPageStarted один раз для основного кадра.Это также означает, что onPageStarted не будет вызываться при изменении содержимого встроенного фрейма, т. Е. При щелчке по ссылке, целью которой является iframe.

Что предполагает, что это может быть вызвано "iframes" ввеб-страница.

...