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


88

我有一个可以广泛使用WebView的应用程序。当此应用程序的用户没有Internet连接时,将显示一个页面,显示“网页不可用”和其他各种文字。有没有办法在我的WebView中不显示此通用文本?我想提供自己的错误处理。

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实际上并未清除视图。


3
为什么在显示webView之前不检查Internet连接,并且如果没有可用的Internet设施,则可以跳过显示WebView的操作,而可以显示警报或吐司而没有Internet消息?
Andro Selva

@JoJo您可以打勾正确的答案吗?可能是我的:P
Sherif elKhatib 2011年

Answers:


102

首先使用HTML创建您自己的错误页面,并将其放入资产文件夹,我们将其称为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");

    }
});

27
旧的“网页未加载”错误页面显示了不到一秒钟的时间,然后被资产中的自定义错误页面替换
Cheenu Madan 2014年

1
同意Cheenu。必须有一个更好的解决方案。
Jozua

3
1.您可以在WebView不可见的情况下加载Web内容(并可能显示进度不良),并在页面成功加载/错误加载“ myerrorpage.html”时显示该内容。2.您应该意识到,如果在加载页面后运行的JS中加载OR问题时遇到问题(例如在document.ready()事件中运行的jQuery函数),onReceiveError将被触发。桌面浏览器-允许JS错误,而不会像移动浏览器那样通知用户。
FunkSoulBrother

5
view.loadUrl("about:blank");在loadUrl之前添加,以防止它在不到一秒钟的时间内显示错误页面。
阿什什语

2
该myerrorpage.html文件放在哪里?该android资产文件夹位于哪里?
尼维德·卡纳达

34

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

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

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

好主意!就我而言,我添加了view.loadUrl(noConnectionUrl);两次(其中noConnectionUrl是带有错误消息的本地文件)。这也有助于在不到一秒钟的时间内“看不到”内置错误页面。
hQuse

4
请注意,如果要处理,请webView.goBack()确保处理此空白页的条件。否则,将加载上一页,如果再次失败,则将再次看到该空白页。
Chintan Shah

那么,什么是最好的处理方法?
MoSoli

@MoSoli这一切都取决于您的需求。显示空白页面的替代方法是显示一些自定义ui或缓存的网页。
7heViking

10

最后,我解决了这个问题。(到现在为止有效。)

我的解决方案是这样的...

  1. 准备布局以显示发生错误的时间,而不是显示Web页面(脏的“未找到页面的消息”)。布局具有一个“ RELOAD”按钮,其中包含一些指导消息。

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

  3. 如果用户单击“重新加载”按钮,则将mbErrorOccured设置为false。并将mbReloadPressed设置为true。
  4. 如果mbErrorOccured为false且mbReloadPressed为true,则表示已成功加载Webview页面。'因为如果再次发生错误,则会在onReceivedError(...)上将mbErrorOccured设置为true

这是我的完整资料。看一下这个。

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>


您能否分享您的资源文件?我是新手。
Rajan Rawal

@RajanRawal我编辑并添加了布局示例。:)
cmcromance

我看不到任何进度条,但是我可以在那看到代码。:-(
Rajan Rawal

7

查看Android WebView onReceivedError()上的讨论。它很长,但是大家似乎一致认为:a)您无法停止出现“网页不可用”页面,但是b)在收到onReceivedError之后,您始终可以加载一个空白页面


这些家伙正在谈论onReceivedError根本不触发。没有互联网连接时,它将在我的代码中正确触发。
乔乔

7

当将Webview嵌入到某些自定义视图中时,用户几乎认为他看到的是本机视图,而不是Web视图,在这种情况下,显示“无法加载页面”错误是荒谬的。在这种情况下,我通常要做的是加载空白页面并显示如下吐司消息

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

2

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


那是个好主意,但是很不幸,我们需要做类似的事情……
Jeffrey Blattman 2012年

2

也许我误解了这个问题,但是听起来您是在说您收到了收到回调的错误,而您只是在问什么是不显示错误的最佳方法?您为什么不只是从屏幕上删除Web视图和/或在其顶部显示另一个视图?


2

在这里,我找到了最简单的解决方案。看看这个。

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

1

我想如果您坚持要这样做,则可以在调用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)

6
在实际进入资源之前检查资源是否存在将使服务器的负载增加一倍,因为每1个虚拟请求将有2个物理请求。这似乎有点矫kill过正。
乔乔

好绝望的措施!
Sherif elKhatib 2011年

1
无论如何,您仍然可以重载它并获取html内容,请检查它是否有错误。如果无法解析并显示它
Sherif elKhatib 2011年

一个人将如何实际实现呢?
JoJo)

@JoJo,实际上,此方法在URL无效的情况下减少了服务器上的负载,因为返回HEAD响应与返回304或500响应相比,开销要小得多。
贾斯汀·希尔德

0

我只是将网页更改为您用于错误处理的内容:

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上找到


0

我一直在努力解决今天抛弃那些烦人的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();
       }
    }
});

如果您将其作为另一个webclient放在shouldOverrideUrlLoading()中。至少,这对我的2.3.6设备有效。稍后我们将在其他地方查看。我敢肯定,那只会让我沮丧。goBack位是我的。您可能不想要它。


0

试试这个

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

0

我们可以将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());
    }

0

我不得不面对这个问题,并且还尝试从不同的角度来解决它。最终,我找到了一个解决方案,方法是使用单个标志检查是否发生了错误。

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

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

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

我避免了加载空页面的解决方案,因为稍后它不允许您执行webview.reload(),因为它会将新页面添加到导航历史记录中。



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.