Prevent WebView from displaying "web page not available"

JavaAndroid

Java Problem Overview


I have an app that makes extensive use of a WebView. When the user of this app does not have Internet connection, a page saying "web page not available" and various other text appears. Is there a way to not show this generic text in my WebView? I would like to provide my own error handling.

private final Activity activity = this;

private class MyWebViewClient extends WebViewClient
 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
  // I need to do something like this:
  activity.webView.wipeOutThePage();
  activity.myCustomErrorHandling();
  Toast.makeText(activity, description, Toast.LENGTH_LONG).show();
 }
}

I found out WebView->clearView doesn't actually clear the view.

Java Solutions


Solution 1 - Java

First create your own error page in HTML and put it in your assets folder, Let's call it myerrorpage.html Then with onReceivedError:

mWebView.setWebViewClient(new WebViewClient() {
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        mWebView.loadUrl("file:///android_asset/myerrorpage.html");

    }
});

Solution 2 - Java

The best solution I have found is to load an empty page in the OnReceivedError event like this:

@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
    super.onReceivedError(view, errorCode, description, failingUrl);

    view.loadUrl("about:blank");
}

Solution 3 - Java

Finally, I solved this. (It works till now..)

My solution is like this...

  1. Prepare the layout to show when an error occurred instead of Web Page (a dirty 'page not found message') The layout has one button, "RELOAD" with some guide messages.

  2. If an error occurred, Remember using boolean and show the layout we prepare.

  3. If user click "RELOAD" button, set mbErrorOccured to false. And Set mbReloadPressed to true.

  4. if mbErrorOccured is false and mbReloadPressed is true, it means webview loaded page successfully. 'Cause if error occurred again, mbErrorOccured will be set true on onReceivedError(...)

Here is my full source. Check this out.

public class MyWebViewActivity extends ActionBarActivity implements OnClickListener {

	private final String TAG = MyWebViewActivity.class.getSimpleName();
	private WebView mWebView = null;
	private final String URL = "http://www.google.com";
	private LinearLayout mlLayoutRequestError = null;
	private Handler mhErrorLayoutHide = null;

	private boolean mbErrorOccured = false;
	private boolean mbReloadPressed = false;

	@SuppressLint("SetJavaScriptEnabled")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_webview);

		((Button) findViewById(R.id.btnRetry)).setOnClickListener(this);
		mlLayoutRequestError = (LinearLayout) findViewById(R.id.lLayoutRequestError);
		mhErrorLayoutHide = getErrorLayoutHideHandler();
		
		mWebView = (WebView) findViewById(R.id.webviewMain);
		mWebView.setWebViewClient(new MyWebViewClient());
		WebSettings settings = mWebView.getSettings();
		settings.setJavaScriptEnabled(true);
		mWebView.setWebChromeClient(getChromeClient());
		mWebView.loadUrl(URL);
	}

	@Override
	public boolean onSupportNavigateUp() {
		return super.onSupportNavigateUp();
	}

	@Override
	public void onClick(View v) {
		int id = v.getId();

		if (id == R.id.btnRetry) {
			if (!mbErrorOccured) {
				return;
			}

			mbReloadPressed = true;
			mWebView.reload();
			mbErrorOccured = false;
		}
	}

	@Override
	public void onBackPressed() {
		if (mWebView.canGoBack()) {
			mWebView.goBack();
			return;
		}
		else {
			finish();
		}

		super.onBackPressed();
	}

	class MyWebViewClient extends 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);
		}

		@Override
		public void onLoadResource(WebView view, String url) {
			super.onLoadResource(view, url);
		}

		@Override
		public void onPageFinished(WebView view, String url) {
			if (mbErrorOccured == false && mbReloadPressed) {
				hideErrorLayout();
				mbReloadPressed = false;
			}

			super.onPageFinished(view, url);
		}

		@Override
		public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
			mbErrorOccured = true;
			showErrorLayout();
			super.onReceivedError(view, errorCode, description, failingUrl);
		}
	}

	private WebChromeClient getChromeClient() {
		final ProgressDialog progressDialog = new ProgressDialog(MyWebViewActivity.this);
		progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
		progressDialog.setCancelable(false);

		return new WebChromeClient() {
			@Override
			public void onProgressChanged(WebView view, int newProgress) {
				super.onProgressChanged(view, newProgress);
			}
		};
	}

	private void showErrorLayout() {
		mlLayoutRequestError.setVisibility(View.VISIBLE);
	}

	private void hideErrorLayout() {
		mhErrorLayoutHide.sendEmptyMessageDelayed(10000, 200);
	}

	private Handler getErrorLayoutHideHandler() {
		return new Handler() {
			@Override
			public void handleMessage(Message msg) {
				mlLayoutRequestError.setVisibility(View.GONE);
				super.handleMessage(msg);
			}
		};
	}
}

Addition:Here is layout....

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rLayoutWithWebView"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<WebView
    android:id="@+id/webviewMain"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<LinearLayout
    android:id="@+id/lLayoutRequestError"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:background="@color/white"
    android:gravity="center"
    android:orientation="vertical"
    android:visibility="gone" >

    <Button
        android:id="@+id/btnRetry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:minWidth="120dp"
        android:text="RELOAD"
        android:textSize="20dp"
        android:textStyle="bold" />
</LinearLayout>

Solution 4 - Java

When webview is embedded in some custom view such that user almost believes that he is seeing a native view and not a webview, in such scenario showing the "page could not be loaded" error is preposterous. What I usually do in such situation is I load blank page and show a toast message as below

webView.setWebViewClient(new WebViewClient() {

			@Override
			public void onReceivedError(WebView view, int errorCode,
					String description, String failingUrl) {
				Log.e(TAG," Error occured while loading the web page at Url"+ failingUrl+"." +description);		
				view.loadUrl("about:blank");
				Toast.makeText(App.getContext(), "Error occured, please check newtwork connectivity", Toast.LENGTH_SHORT).show();
				super.onReceivedError(view, errorCode, description, failingUrl);
			}
		});

Solution 5 - Java

Check out the discussion at https://stackoverflow.com/questions/4997677/android-webview-onreceivederror. It's quite long, but the consensus seems to be that a) you can't stop the "web page not available" page appearing, but b) you could always load an empty page after you get an onReceivedError

Solution 6 - Java

You could use a GET request to get the page content and then display that data using the Webview , this way you are not using multiple server calls. Alternative you can use Javascript to check the DOM object for validity.

Solution 7 - Java

Perhaps I misunderstand the question, but it sounds like you're saying you get the error received callback, and you just are asking what is the best way to not show the error? Why don't you just either remove the web view from the screen and/or show another view on top of it?

Solution 8 - Java

Here I found the easiest solution. check out this..

   @Override
        public void onReceivedError(WebView view, int errorCode,
                                    String description, String failingUrl) {
//                view.loadUrl("about:blank");
            mWebView.stopLoading();
            if (!mUtils.isInterentConnection()) {
                Toast.makeText(ReportingActivity.this, "Please Check Internet Connection!", Toast.LENGTH_SHORT).show();
            }
            super.onReceivedError(view, errorCode, description, failingUrl);
        }

And here is isInterentConnection() method...

public boolean isInterentConnection() {
    ConnectivityManager manager = (ConnectivityManager) mContext
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    if (manager != null) {
        NetworkInfo info[] = manager.getAllNetworkInfo();
        if (info != null) {
            for (int i = 0; i < info.length; i++) {
                if (info[i].getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
    }
    return false;
}

Solution 9 - Java

I suppose that if you insist on doing this, you could just check if the resource is there before calling the loadURL function. Just simply override the functions and do the check before calling the super()

REMARK (maybe off-topic): In http, there is a method called HEAD which is described as follow:

> The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response

This method might be handy. Anyway how ever you implement it ... check this code:

import java.util.Map;

import android.content.Context;
import android.webkit.WebView;

public class WebViewPreLoad extends WebView{

public WebViewPreLoad(Context context) {
super(context);
}
public void loadUrl(String str){
if(//Check if exists)
super.loadUrl(str);
else
//handle error
}
public void loadUrl(String url, Map<String,String> extraHeaders){
if(//Check if exists)
super.loadUrl(url, extraHeaders);
else
//handle error
}
}

You could try this check using

if(url.openConnection().getContentLength() > 0)

Solution 10 - Java

I would just change the webpage to whatever you are using for error handling:

getWindow().requestFeature(Window.FEATURE_PROGRESS);  
webview.getSettings().setJavaScriptEnabled(true);  
final Activity activity = this;  
webview.setWebChromeClient(new WebChromeClient() {  
public void onProgressChanged(WebView view, int progress) {  
 // Activities and WebViews measure progress with different scales.  
 // The progress meter will automatically disappear when we reach 100%  
 activity.setProgress(progress * 1000);  
 }  
});  
webview.setWebViewClient(new WebViewClient() {  
public void onReceivedError(WebView view, int errorCode, String description, String 
failingUrl) {  
 Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();  
}  
});  
webview.loadUrl("http://slashdot.org/");

this can all be found on http://developer.android.com/reference/android/webkit/WebView.html

Solution 11 - Java

I've been working on this problem of ditching those irritable Google error pages today. It is possible with the Android example code seen above and in plenty of other forums (ask how I know):

wv.setWebViewClient(new WebViewClient() {
    public void onReceivedError(WebView view, int errorCode,
                            String description, String failingUrl) {
       if (view.canGoBack()) {
          view.goBack();
        }
       Toast.makeText(getBaseContext(), description, Toast.LENGTH_LONG).show();
       }
    }
});

IF you put it in shouldOverrideUrlLoading() as one more webclient. At least, this is working for me on my 2.3.6 device. We'll see where else it works later. That would only depress me now, I'm sure. The goBack bit is mine. You may not want it.

Solution 12 - Java

Try this

 @SuppressWarnings("deprecation")
 @Override
 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
      // Your handling
 }

 @Override
 public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
      }
 }

Solution 13 - Java

We can set the visibility of webView to 0(view.INVISIBLE) and show some message. This code works for my app running on lolipop.

@SuppressWarnings("deprecation")
    @Override
    public void onReceivedError(WebView webView, int errorCode, String description, String failingUrl) {
        // hide webView content and show custom msg
        webView.setVisibility(View.INVISIBLE);
        Toast.makeText(NrumWebViewActivity.this,getString(R.string.server_not_responding), Toast.LENGTH_SHORT).show();
    }

    @TargetApi(android.os.Build.VERSION_CODES.M)
    @Override
    public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
        // Redirect to deprecated method, so you can use it in all SDK versions
        onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
    }

Solution 14 - Java

I've had to face this issue and also tried to solve it from different perspectives. Finally I found a solution by using a single flag to check if an error happened.

... extends WebViewClient {

	boolean error;

 	@Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
   
        showLoading(true);
        super.onPageStarted(view, url, favicon);
        
        error  = false; // IMPORTANT
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
         
        if(!error) {
            Observable.timer(100, TimeUnit.MICROSECONDS, AndroidSchedulers.mainThread())
                    .subscribe((data) -> view.setVisibility(View.VISIBLE) );
        }

        showLoading(false);
    }


    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {

        view.stopLoading();

        view.setVisibility(View.INVISIBLE) 
        error  = true;  

        // Handle the error
    }


     @Override
    @TargetApi(android.os.Build.VERSION_CODES.M)
    public void onReceivedError(WebView view,
                                WebResourceRequest request,
                                WebResourceError error) {

        this.onReceivedError(view, error.getErrorCode(),
                error.getDescription().toString(),
                request.getUrl().toString());
    }
 }

This way I hide the page every time there's an error and show it when the page has loaded again properly.

Also added a small delay in case.

I avoided the solution of loading an empty page as it does not allow you to do webview.reload() later on due to it adds that new page in the navigation history.

Solution 15 - Java

try this shouldOverrideUrlLoading , before redirect to another url check for internet conncetion based on that page should be loaded or not.

Solution 16 - Java

override your WebViewClient method

@Override
public void onReceivedError(WebView view, int errorCode,
	String description, String failingUrl) {
	view.clearView();
}

view.loadUrl('about:blank') has side-effects, as it cancels the original URL loading.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoJoView Question on Stackoverflow
Solution 1 - JavaSnowboardBruinView Answer on Stackoverflow
Solution 2 - Java7heVikingView Answer on Stackoverflow
Solution 3 - JavacmcromanceView Answer on Stackoverflow
Solution 4 - JavaJeevanView Answer on Stackoverflow
Solution 5 - JavaToridView Answer on Stackoverflow
Solution 6 - JavaRavi VyasView Answer on Stackoverflow
Solution 7 - JavaMatthew HorstView Answer on Stackoverflow
Solution 8 - JavaAnkush JoshiView Answer on Stackoverflow
Solution 9 - JavaSherif elKhatibView Answer on Stackoverflow
Solution 10 - JavaEphraimView Answer on Stackoverflow
Solution 11 - JavaR Earle HarrisView Answer on Stackoverflow
Solution 12 - JavaVirat18View Answer on Stackoverflow
Solution 13 - JavaMahenView Answer on Stackoverflow
Solution 14 - JavaJose M LechonView Answer on Stackoverflow
Solution 15 - JavaBipin VayaluView Answer on Stackoverflow
Solution 16 - JavaduckduckgoView Answer on Stackoverflow