【问题标题】:Prevent WebView from displaying "web page not available"防止 WebView 显示“网页不可用”
【发布时间】:2011-07-01 18:58:50
【问题描述】:

我有一个广泛使用 WebView 的应用程序。当这个应用程序的用户没有互联网连接时,会出现一个页面说“网页不可用”和其他各种文字。有没有办法不在我的 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 实际上并没有清除视图。

【问题讨论】:

  • 为什么不在显示 webView 之前检查互联网连接,如果没有可用的互联网设施,您可以跳过显示 WebView,而是在没有互联网消息的情况下显示警报或 toast?跨度>
  • @JoJo 你能把答案打勾吗?可能是我的:P

标签: java android


【解决方案1】:

首先在 HTML 中创建你自己的错误页面,并将它放在你的 assets 文件夹中,我们称之为 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");

    }
});

【讨论】:

  • 旧的“网页未加载”错误页面显示几分之一秒,然后被资产中的自定义错误页面替换
  • 同意切努。必须有更好的解决方案。
  • 1.您可以在 WebView 不可见时加载 Web 内容(并且可能会在其上显示错误的进度),并在页面加载成功时显示它/在错误时加载“myerrorpage.html”。 2. 您应该知道,如果在页面加载后运行的 JS 中加载 OR 问题时出现问题(例如在 document.ready() 事件中运行的 jQuery 函数),将触发 onReceiveError。桌面浏览器 - 将允许 JS 错误而不通知用户,就像移动浏览器一样。
  • 在 loadUrl 之前添加 view.loadUrl("about:blank"); 以防止它在几分之一秒内显示错误页面。
  • 把 myerrorpage.html 文件放在哪里?那个 android assets 文件夹在哪里?
【解决方案2】:

我发现的最佳解决方案是在 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 是带有错误消息的本地文件)。这也有助于在几分之一秒内“看不到”内置错误页面。
  • 请注意,如果您正在处理webView.goBack(),请确保处理此空白页的条件。否则你的上一个页面将被加载,如果再次失败,你将再次看到这个空白页面。
  • 那么,最好的处理方法是什么?
  • @MoSoli 这完全取决于您的需求。显示空白页面的替代方法是显示一些自定义 ui 或缓存网页。
【解决方案3】:

最后,我解决了这个问题。 (它一直有效..)

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

  1. 准备布局以显示何时发生错误而不是网页(脏的“未找到页面消息”)该布局有一个按钮,“重新加载”和一些指导消息。

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

  3. 如果用户单击“重新加载”按钮,请将 mbErrorOccured 设置为 false。并将 mbReloadPressed 设置为 true。
  4. 如果 mbErrorOccured 为 false 且 mbReloadPressed 为 true,则表示 webview 加载页面成功。 '因为如果再次发生错误,mbErrorOccured 将在 onReceivedError(...) 上设置为 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>

【讨论】:

  • 你能分享你的资源文件吗?我是新手。
  • @RajanRawal 我编辑并添加了布局示例。 :)
  • 我看不到任何进度条,但我可以看到那里的代码。 :-(
【解决方案4】:

当 webview 嵌入到一些自定义视图中时,用户几乎认为他看到的是本机视图而不是 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);
            }
        });

【讨论】:

    【解决方案5】:

    查看Android WebView onReceivedError() 的讨论。这很长,但共识似乎是a)您无法阻止“网页不可用”页面出现,但是b)您总是可以在收到onReceivedError后加载一个空页面

    【讨论】:

    • 这些家伙在谈论 onReceivedError 根本没有触发。当没有 Internet 连接时,它会在我的代码中正确触发。
    【解决方案6】:

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

    【讨论】:

    • 这是个好主意,但是很不幸我们需要做这样的事情......
    【解决方案7】:

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

    【讨论】:

      【解决方案8】:

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

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

      【讨论】:

        【解决方案9】:

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

        REMARK(可能跑题了):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)
        

        【讨论】:

        • 在实际去那里之前检查资源是否存在会使服务器上的负载加倍,因为每 1 个虚拟请求会有 2 个物理请求。这似乎有点矫枉过正。
        • 无论如何你仍然可以重载它并获取html内容,检查它是否有错误。如果不解析并显示它
        • 如何实际实现这一点?
        • @JoJo,实际上这种方法减少了在无效 url 的情况下服务器的负载,因为返回 HEAD 响应与返回 304 或 500 响应相比,开销要小得多。
        • 如果在下载页面时连接断开,这并不能解决问题
        【解决方案10】:

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

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

        【讨论】:

          【解决方案11】:

          我今天一直在努力解决放弃那些烦人的 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。至少,这在我的 2.3.6 设备上对我有用。我们稍后会看到它在哪里工作。我敢肯定,那只会让我现在感到沮丧。 goBack 位是我的。你可能不想要它。

          【讨论】:

            【解决方案12】:

            试试这个

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

            【讨论】:

              【解决方案13】:

              我们可以将 webView 的可见性设置为 0(view.INVISIBLE) 并显示一些消息。 此代码适用于我在棒棒糖上运行的应用程序。

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

              【讨论】:

                【解决方案14】:

                我不得不面对这个问题,也试图从不同的角度来解决它。最后,我通过使用单个标志来检查是否发生错误找到了解决方案。

                ... 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(),因为它会在导航历史记录中添加新页面。

                【讨论】:

                  【解决方案15】:

                  试试这个shouldOverrideUrlLoading,在重定向到另一个网址之前检查是否应该加载基于该页面的互联网连接。

                  【讨论】:

                    【解决方案16】:

                    覆盖您的 WebViewClient 方法

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

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

                    【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-10-07
                    • 2023-03-20
                    • 1970-01-01
                    相关资源
                    最近更新 更多