Ngăn WebView hiển thị "trang web không khả dụng"


88

Tôi có một ứng dụng sử dụng rộng rãi WebView. Khi người dùng ứng dụng này không có kết nối Internet, một trang thông báo "trang web không khả dụng" và nhiều văn bản khác sẽ xuất hiện. Có cách nào để không hiển thị văn bản chung này trong WebView của tôi không? Tôi muốn cung cấp cách xử lý lỗi của riêng tôi.

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

Tôi phát hiện ra rằng WebView-> clearView không thực sự xóa chế độ xem.


3
Tại sao bạn không kiểm tra kết nối internet trước khi hiển thị webView và nếu không có thiết bị internet, bạn có thể bỏ qua hiển thị WebView và thay vào đó bạn có thể hiển thị cảnh báo hoặc bánh mì nướng mà không có tin nhắn internet?
Andro Selva,

@JoJo bạn có thể đánh dấu vào một câu trả lời là đúng không? có lẽ tôi: P
Sherif elKhatib

Câu trả lời:


102

Đầu tiên, hãy tạo trang lỗi của riêng bạn trong HTML và đặt nó vào thư mục nội dung của bạn, Hãy gọi nó là myerrorpage.html Sau đó với onReceiveError:

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

    }
});

27
Cũ "Trang web không được tải" chương trình trang lỗi cho một phần nhỏ của một giây trước khi bị thay thế bởi các trang lỗi tùy chỉnh từ tài sản
Cheenu Madan

1
Đồng ý với Cheenu. Phải có một giải pháp tốt hơn.
Jozua

3
1. Bạn có thể tải nội dung web trong khi WebView đang ẩn (và có thể hiển thị tiến trình xấu trên nó) và hiển thị nó nếu trang được tải thành công / tải "myerrorpage.html" do lỗi. 2. Bạn nên biết rằng onReceiveError sẽ được kích hoạt nếu có vấn đề khi tải vấn đề HOẶC trong JS chạy sau khi trang đã được tải (như các hàm jQuery chạy trong sự kiện document.ready ()). Trình duyệt máy tính để bàn - sẽ cho phép lỗi JS mà không cần thông báo cho người dùng về nó, cũng như các trình duyệt di động cũng vậy.
FunkSoulBrother

5
thêm view.loadUrl("about:blank");trước loadUrl để ngăn nó hiển thị trang lỗi trong một phần giây.
Aashish

2
Đặt tệp myerrorpage.html đó ở đâu? Thư mục nội dung android đó nằm ở đâu?
Nived Kannada

34

Giải pháp tốt nhất mà tôi đã tìm thấy là tải một trang trống trong sự kiện OnReceiveError như sau:

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

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

Ý tưởng tốt! Trong trường hợp của tôi, tôi đã thêm view.loadUrl(noConnectionUrl);hai lần (trong đó noConnectionUrl là tệp cục bộ có thông báo lỗi). Điều đó cũng giúp không "nhìn thấy" trang lỗi tích hợp trong một phần giây.
hQuse

4
Xin lưu ý rằng, nếu bạn đang xử lý webView.goBack()thì hãy đảm bảo xử lý điều kiện cho trang trống này. Nếu không, trang trước của bạn sẽ được tải và nếu không thành công lần nữa thì bạn sẽ thấy lại trang trống này.
Chintan Shah

Vì vậy, cách tốt nhất để xử lý nó là gì?
MoSoli

@MoSoli Tất cả phụ thuộc vào nhu cầu của bạn. Một giải pháp thay thế để hiển thị một trang trống sẽ là hiển thị một số ui tùy chỉnh hoặc một trang web được lưu trong bộ nhớ cache.
7heViking

10

Cuối cùng, tôi đã giải quyết được điều này. (Nó hoạt động cho đến bây giờ ..)

Giải pháp của tôi là như thế này ...

  1. Chuẩn bị bố cục để hiển thị khi xảy ra lỗi thay vì Trang web (thông báo 'không tìm thấy trang' bẩn) Bố cục có một nút, "RELOAD" với một số thông báo hướng dẫn.

  2. Nếu xảy ra lỗi, hãy nhớ sử dụng boolean và hiển thị bố cục chúng tôi chuẩn bị.

  3. Nếu người dùng nhấp vào nút "RELOAD", hãy đặt mbErrorOccured thành false. Và Đặt mbReloadPressed thành true.
  4. nếu mbErrorOccured là false và mbReloadPressed là true, điều đó có nghĩa là trang web đã tải thành công. Vì nếu lỗi lại xảy ra, mbErrorOccured sẽ được đặt thành true trên onReceiveError (...)

Đây là nguồn đầy đủ của tôi. Kiểm tra điều này.

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

Bổ sung: Đây là bố cục ....

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


Bạn có thể vui lòng chia sẻ tệp tài nguyên của bạn được không? Tôi là người mới.
Rajan Rawal,

@RajanRawal Tôi đã chỉnh sửa và thêm ví dụ về bố cục. :)
cmcromance

Tôi không thể thấy bất kỳ thanh tiến trình nào, nhưng tôi có thể thấy mã ở đó. :-(
Rajan Rawal,

7

Khi chế độ xem web được nhúng vào một số chế độ xem tùy chỉnh mà người dùng gần như tin rằng anh ta đang xem chế độ xem gốc chứ không phải chế độ xem web, trong trường hợp như vậy, lỗi "không thể tải trang" là vô lý. Những gì tôi thường làm trong tình huống như vậy là tôi tải trang trống và hiển thị thông báo nâng ly như bên dưới

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

6

Kiểm tra cuộc thảo luận tại Android WebView onReceiveError () . Nó khá dài, nhưng sự đồng thuận dường như là a) bạn không thể ngăn trang "trang web không khả dụng" xuất hiện, nhưng b) bạn luôn có thể tải một trang trống sau khi gặp lỗi onReceiveError


Những kẻ này đang nói về việc hoàn toàn onReceivedErrorkhông kích hoạt. Nó kích hoạt chính xác trong mã của tôi khi không có kết nối Internet.
JoJo

2

Bạn có thể sử dụng một GETyêu cầu để lấy nội dung trang và sau đó hiển thị dữ liệu đó bằng cách sử dụng Webview, theo cách này, bạn không sử dụng nhiều lệnh gọi máy chủ. Bạn có thể sử dụng Javascriptcách khác để kiểm tra DOMtính hợp lệ của đối tượng.


đó là một ý tưởng tốt, tuy nhiên, nó thực sự không may, chúng tôi cần phải làm một cái gì đó như thế này ...
Jeffrey Blattman

2

Có lẽ tôi hiểu sai câu hỏi, nhưng có vẻ như bạn đang nói rằng bạn gặp lỗi khi nhận được cuộc gọi lại và bạn chỉ đang hỏi cách tốt nhất để không hiển thị lỗi là gì? Tại sao bạn không xóa chế độ xem web khỏi màn hình và / hoặc hiển thị một chế độ xem khác trên đó?


2

Ở đây tôi đã tìm thấy giải pháp dễ dàng nhất. kiểm tra này ..

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

Và đây là phương thức 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

Tôi cho rằng nếu bạn khăng khăng làm điều này, bạn chỉ cần kiểm tra xem tài nguyên có ở đó hay không trước khi gọi hàm loadURL. Chỉ cần ghi đè các hàm và kiểm tra trước khi gọi hàm super ()

NHẬN XÉT (có thể lạc đề): Trong http, có một phương pháp được gọi là HEAD được mô tả như sau:

Phương thức HEAD giống với GET ngoại trừ việc máy chủ KHÔNG PHẢI trả lại nội dung thư trong phản hồi

Phương pháp này có thể hữu ích. Dù sao thì bao giờ bạn triển khai nó ... hãy kiểm tra mã này:

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

Bạn có thể thử kiểm tra này bằng cách sử dụng

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

6
Việc kiểm tra xem tài nguyên có ở đó hay không trước khi thực sự đến đó sẽ tăng gấp đôi tải trên máy chủ vì sẽ có 2 yêu cầu vật lý trên 1 yêu cầu ảo. Điều này có vẻ hơi quá mức cần thiết.
JoJo

cũng tuyệt vọng các biện pháp!
Sherif elKhatib

1
Dù sao thì bạn vẫn có thể quá tải nó và lấy nội dung html ,, hãy kiểm tra xem nó có bị lỗi không. Nếu không được phân tích và hiển thị nó
Sherif elKhatib

làm thế nào một người thực sự sẽ thực hiện điều này?
JoJo

@JoJo, thực ra phương pháp này giảm tải trên máy chủ trong trường hợp url không hợp lệ vì trả về phản hồi HEAD có chi phí nhỏ hơn nhiều so với trả về phản hồi 304 hoặc 500.
Justin Shield

0

Tôi chỉ muốn thay đổi trang web thành bất cứ thứ gì bạn đang sử dụng để xử lý lỗi:

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/");

tất cả điều này có thể được tìm thấy trên http://developer.android.com/reference/android/webkit/WebView.html


0

Hôm nay, tôi đang giải quyết vấn đề loại bỏ các trang lỗi khó chịu của Google. Có thể thực hiện được với mã ví dụ Android được thấy ở trên và trong nhiều diễn đàn khác (hỏi cách tôi biết):

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

NẾU bạn đặt nó vào shouldOverrideUrlLoading () như một webclient khác. Ít nhất, điều này đang hoạt động đối với tôi trên thiết bị 2.3.6 của tôi. Chúng ta sẽ xem nó hoạt động ở đâu khác sau. Tôi chắc rằng điều đó sẽ chỉ khiến tôi chán nản. Bit goBack là của tôi. Bạn có thể không muốn nó.


0

Thử cái này

 @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

Chúng ta có thể đặt khả năng hiển thị của webView thành 0 (view.INVISIBLE) và hiển thị một số thông báo. Mã này hoạt động cho ứng dụng của tôi đang chạy trên 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

Tôi đã phải đối mặt với vấn đề này và cũng cố gắng giải quyết nó từ những khía cạnh khác nhau. Cuối cùng tôi đã tìm ra giải pháp bằng cách sử dụng một lá cờ duy nhất để kiểm tra xem có lỗi xảy ra hay không.

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

Bằng cách này, tôi ẩn trang mỗi khi có lỗi và hiển thị khi trang đã tải lại đúng cách.

Cũng thêm một sự chậm trễ nhỏ trong trường hợp.

Tôi đã tránh giải pháp tải một trang trống vì nó không cho phép bạn thực hiện webview.reload () sau này do nó thêm trang mới đó vào lịch sử điều hướng.


-1

hãy thử điều này nênOverrideUrlLoading , trước khi chuyển hướng đến một url khác, hãy kiểm tra sự kết nối internet dựa trên trang đó có được tải hay không.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.