防止WebView显示“网页不可用”

我有一个应用程序,广泛使用的WebView。 当这个应用程序的用户没有互联网连接,出现一个网页说“网页不可用”和其他各种文字。 有没有办法在我的WebView中不显示这个通用文本? 我想提供我自己的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(); } } 

我发现WebView-> clearView实际上并不清除视图。

Solutions Collecting From Web of "防止WebView显示“网页不可用”"

首先在HTML中创build自己的错误页面,并将其放在资产文件夹中,让我们称之为myerrorpage.html然后用onReceivedError:

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

我发现最好的解决scheme是加载OnReceivedError事件中的空白页面,如下所示:

 @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); view.loadUrl("about:blank"); } 

最后,我解决了这个问题。 (它工作到现在..)

我的解决scheme是这样的…

  1. 准备布局以显示发生错误的时间,而不是网页(一个脏的“找不到页面的消息”)布局有一个button,“RELOAD”和一些指导消息。

  2. 如果发生错误,请记住使用布尔值并显示我们准备的布局。

  3. 如果用户点击“RELOAD”button,将mbErrorOccured设置为false。 并将mbReloadPressed设置为true。
  4. 如果mbErrorOccured为false且mbReloadPressed为true,则表示webview已成功加载页面。 因为如果再次发生错误,mbErrorOccured将被设置为onReceivedError(…)

这是我的全部来源。 看一下这个。

 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); } }; } } 

另外:这是布局….

 <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> 

查看Android WebView onReceivedError()的讨论。 这是相当长的,但共识似乎是,a)你不能停止“网页不可用”页面出现,但b)你总是可以加载一个空的页面后,你得到一个onReceivedError

当webview被embedded到一些自定义视图中时,用户几乎认为他看到的是本地视图而不是webview。 在这样的情况下,显示“页面无法加载”的错误是荒谬的,我通常在这种情况下做的是我加载空白页面,并显示敬酒信息如下

 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); } }); 

您可以使用GET请求获取页面内容,然后使用Webview显示该数据,这样您就不会使用多个服务器调用。 另外,你可以使用Javascript来检查DOM对象的有效性。

也许我误解了这个问题,但是这听起来像是在说你得到了callback错误,而你只是在问什么是不显示错误的最好方法? 为什么不只是从屏幕上删除网页视图和/或在其上显示另一个视图呢?

我想如果你坚持这样做,你可以在调用loadURL函数之前检查资源是否在那里。 只需简单地覆盖函数,并在调用super()之前进行检查

备注(也许是题外话):在http中,有一种叫HEAD的方法,描述如下:

HEAD方法与GET相同,只是服务器不能在响应中返回消息体

这种方法可能是方便的。 无论如何,你怎么实现它…检查此代码:

 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 } } 

你可以尝试使用这个检查

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

我只是将网页更改为任何您正在使用的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/"); 

这可以在http://developer.android.com/reference/android/webkit/WebView.html上find

我一直在努力解决这个烦人的Google错误页面的问题。 在上面看到的Android示例代码以及其他许多论坛中可以这样做(请问我是怎么知道的):

 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(); } } }); 

如果你把它放在shouldOverrideUrlLoading()作为一个更多的webclient。 至less,这是在我的2.3.6设备上工作。 我们稍后会看到它还有什么作用。 我相信现在只会让我感到压抑。 goBack位是我的。 你可能不需要它。

尝试这个

  @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()); } } 

我们可以将webView的可见性设置为0(view.INVISIBLE)并显示一些消息。 此代码适用于我的应用程序在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()); } 

在这里我find了最简单的解决scheme。 看看这个..

  @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); } 

这里是isInterentConnection()方法…

 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; } 

我不得不面对这个问题,也试图从不同的angular度来解决这个问题。 最后,我find了一个解决scheme,使用一个单一的标志来检查是否发生错误。

 ... 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()); } } 

这样,每次出现错误时我都会隐藏页面,并在页面正确再次加载时显示。

还加了一个小小的延迟情况。

我避免了加载空白页面的解决scheme,因为它不允许您稍后再执行webview.reload(),因为它会在导航历史logging中添加新的页面。

试试这个shouldOverrideUrlLoading之前,redirect到另一个url检查基于该网页的互联网conncetion应该加载或不。

重写您的WebViewClient方法

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

view.loadUrl('about:blank')有副作用,因为它取消了原始的URL加载。