WebViewClient.onPageStarted () вызывается дважды при указании несуществующего URL через WebView.loadURL ()

Вот мой код

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

Я столкнулся с такой же проблемой при тестировании моего приложения на 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.

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

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

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

Это говорит о том, что это может быть вызвано «iframes» на веб-странице.