2011-07-01 92 views
72

我有一個可以廣泛使用WebView的應用程序。當這個應用程序的用戶沒有互聯網連接時,會出現一個頁面,顯示「網頁不可用」和其他各種文本。有沒有辦法在我的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實際上並沒有清除視圖。

+2

爲什麼不在顯示webView之前檢查互聯網連接,如果沒有可用的互聯網設施,您可以跳過顯示WebView,而是可以顯示沒有互聯網消息的警報或烤麪包? –

+0

@JoJo你能選擇正確的答案嗎?大概是我的:P –

回答

83

首先在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"); 

    } 
}); 
+18

舊的「網頁未加載」錯誤頁面顯示爲秒之前被資產中的自定義錯誤頁面替換 –

+0

同意Cheenu。必須有更好的解決方案。 – Jozua

+3

1.您可以在WebView不可見的情況下加載Web內容(並且可能會顯示一個糟糕的進度),並在頁面加載成功時顯示它,並在錯誤時載入「myerrorpage.html」。 2.您應該意識到,如果在加載頁面後運行的JS中加載OR問題時出現問題(例如在document.ready()事件中運行的jQuery函數),則會觸發onReceiveError。桌面瀏覽器 - 將允許JS錯誤,而不會通知用戶它,如移動瀏覽器一樣。 – FunkSoulBrother

6

查看Android WebView onReceivedError()的討論。這是相當長的,但共識似乎是a)你不能停止「網頁不可用」頁面出現,但b)你總是可以加載一個空的頁面後,你收到onReceivedError

+0

這些傢伙都在談論'onReceivedError'根本沒有觸發。當沒有Internet連接時,它在我的代碼中正確觸發。 – JoJo

1

我想這如果你堅持這樣做,你可以在調用loadURL函數之前檢查資源是否存在。 只需簡單地覆蓋功能和調用超()

備註(也許題外話)之前做的檢查:在HTTP中,有被描述爲如下的方法稱爲HEAD:

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

這種方法可能很方便。 反正怎麼過你實現它...檢查這個代碼:

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) 
+5

在實際上去那裏之前檢查資源是否存在會使服務器上的負載加倍,因爲每個虛擬請求會有2個物理請求。這似乎有點矯枉過正。 – JoJo

+0

好絕望的措施! –

+1

無論如何,你仍然可以重載它並獲取html內容,請檢查它是否有錯誤。如果不解析並顯示它 –

2

你可以使用一個GET請求獲得頁面內容試試這個檢查,然後顯示數據使用Webview,這樣你就不會使用多個服務器調用。或者,您可以使用Javascript檢查DOM對象的有效性。

+0

這是一個好主意,但是,真的很不幸,我們需要做這樣的事情...... –

-1

試試這個shouldOverrideUrlLoading,在重定向到另一個url之前檢查基於該頁面的網絡連接是否應該被加載。

2

也許我誤解了這個問題,但它聽起來像是在說你得到了回調錯誤,而你只是在問什麼是不顯示錯誤的最佳方式?你爲什麼不直接從屏幕上移除Web視圖和/或在其上顯示另一個視圖?

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

,如果你把它shouldOverrideUrlLoading()作爲一個更WebClient的。至少,這是我的2.3.6設備上的工作。我們稍後會看到它在哪裏工作。我相信現在只會讓我感到壓抑。 goBack位是我的。你可能不需要它。

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

最後,我解決了這個。 (它的工作原理到現在爲止..)

我的解決辦法是這樣的......

  1. 準備佈局顯示時出現的,而不是網頁(髒「找不到網頁信息」)的錯誤佈局有一個按鈕,「RELOAD」和一些指導信息。

  2. 如果發生錯誤,請記住使用布爾值並顯示我們準備的佈局。

  3. 如果用戶點擊「RELOAD」按鈕,將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> 

+0

你能分享你的資源文件嗎?我是新手。 –

+0

@RajanRawal我編輯並添加了佈局示例。 :) – cmcromance

+0

我看不到任何進度條,但我可以在那裏看到代碼。 :-( –

-1

覆蓋您WebViewClient方法

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

view.loadUrl('about:blank')有副作用,因爲它取消了原有的網址加載。

+0

view.clearView()已被棄用,請參閱http://stackoverflow.com/questions/3715482/clear-webview-content – silva96

21

我已經找到了最好的解決辦法是在OnReceivedError事件這樣加載一個空白頁:

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

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

好主意! 在我的情況下,我添加了'view.loadUrl(noConnectionUrl);'兩次(其中noConnectionUrl是帶有錯誤消息的本地文件) 這也有助於在幾分之一秒內「看見」內置錯誤頁面。 – hQuse

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

我們可以web視圖的可見性設置爲0(查看.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()); 
    } 
1

在這裏,我找到了最簡單的解決方案。看看這個..

@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; 
} 
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(),因爲它會在導航歷史記錄中添加新頁面。