Verhindern Sie, dass WebView "Webseite nicht verfügbar" anzeigt.

88

Ich habe eine App, die ein WebView in großem Umfang nutzt. Wenn der Benutzer dieser App keine Internetverbindung hat, wird eine Seite mit der Aufschrift "Webseite nicht verfügbar" und verschiedenen anderen Texten angezeigt. Gibt es eine Möglichkeit, diesen generischen Text in meinem WebView nicht anzuzeigen? Ich möchte meine eigene Fehlerbehandlung bereitstellen.

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

Ich habe herausgefunden, dass WebView-> clearView die Ansicht nicht wirklich löscht .

JoJo
quelle
3
Warum überprüfen Sie nicht die Internetverbindung, bevor Sie das WebView anzeigen. Wenn keine Internetfunktion verfügbar ist, können Sie das Anzeigen des WebView überspringen und stattdessen eine Warnung oder einen Toast ohne Internetnachricht anzeigen.
Andro Selva
@JoJo kannst du eine Antwort als richtig ankreuzen? wahrscheinlich meins: P
Sherif elKhatib

Antworten:

102

Erstellen Sie zuerst Ihre eigene Fehlerseite in HTML und legen Sie sie in Ihrem Assets-Ordner ab. Nennen wir sie myerrorpage.html. Dann mit onReceivedError:

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

    }
});
SnowboardBruin
quelle
27
Die alte Fehlerseite "Webseite nicht geladen" wird für den Bruchteil einer Sekunde
angezeigt,
1
Stimme Cheenu zu. Es muss eine bessere Lösung geben.
Jozua
3
1. Sie können den Webinhalt laden, während die WebView unsichtbar ist (und möglicherweise einen schlechten Fortschritt anzeigen) und ihn anzeigen, wenn die Seite erfolgreich geladen wurde / "myerrorpage.html" bei einem Fehler laden. 2. Sie sollten sich bewusst sein, dass onReceiveError ausgelöst wird, wenn beim Laden des ODER-Problems in JS, das nach dem Laden der Seite ausgeführt wird, Probleme auftreten (wie bei jQuery-Funktionen, die im Ereignis document.ready () ausgeführt werden). Desktop-Browser - Ermöglicht JS-Fehler, ohne den Benutzer darüber zu informieren, wie dies bei mobilen Browsern der Fall ist.
FunkSoulBrother
5
view.loadUrl("about:blank");Fügen Sie vor loadUrl hinzu, um zu verhindern, dass die Fehlerseite für den Bruchteil einer Sekunde angezeigt wird.
Aashish
2
Wo soll diese myerrorpage.html-Datei abgelegt werden? Wo befindet sich dieser Android-Assets-Ordner?
Nived Kannada
34

Die beste Lösung, die ich gefunden habe, besteht darin, eine leere Seite in das OnReceivedError-Ereignis wie folgt zu laden:

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

    view.loadUrl("about:blank");
}
7heViking
quelle
Gute Idee! In meinem Fall habe ich view.loadUrl(noConnectionUrl);zweimal hinzugefügt (wobei noConnectionUrl eine lokale Datei mit Fehlermeldung ist). Dies half auch, die eingebaute Fehlerseite für den Bruchteil einer Sekunde nicht zu "sehen".
hQuse
4
Bitte beachten Sie, dass Sie webView.goBack()bei der Bearbeitung die Bedingungen für diese leere Seite berücksichtigen müssen. Andernfalls wird Ihre vorherige Seite geladen. Wenn dies erneut fehlschlägt, wird diese leere Seite erneut angezeigt.
Chintan Shah
Also, was ist der beste Weg, um damit umzugehen?
MoSoli
@MoSoli Es hängt alles von Ihren Bedürfnissen ab. Eine Alternative zum Anzeigen einer leeren Seite wäre das Anzeigen einer benutzerdefinierten Benutzeroberfläche oder einer zwischengespeicherten Webseite.
7heViking
10

Schließlich habe ich das gelöst. (Es funktioniert bis jetzt ..)

Meine Lösung ist wie folgt ...

  1. Bereiten Sie das Layout so vor, dass angezeigt wird, wann ein Fehler anstelle der Webseite aufgetreten ist (eine schmutzige Meldung "Seite nicht gefunden"). Das Layout verfügt über eine Schaltfläche "RELOAD" mit einigen Leitmeldungen.

  2. Wenn ein Fehler aufgetreten ist, denken Sie daran, Boolesche Werte zu verwenden, und zeigen Sie das von uns vorbereitete Layout an.

  3. Wenn der Benutzer auf die Schaltfläche "RELOAD" klickt, setzen Sie mbErrorOccured auf false. Und setzen Sie mbReloadPressed auf true.
  4. Wenn mbErrorOccured false und mbReloadPressed true ist, bedeutet dies, dass die Webview-Seite erfolgreich geladen wurde. Denn wenn der Fehler erneut auftritt, wird mbErrorOccured bei onReceivedError (...) auf true gesetzt.

Hier ist meine vollständige Quelle. Überprüfen Sie dies heraus.

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

Ergänzung: Hier ist Layout ....

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

cmcromance
quelle
Können Sie bitte Ihre Ressourcendatei freigeben? Ich bin Neuling.
Rajan Rawal
@ RajanRawal Ich habe das Layout-Beispiel bearbeitet und hinzugefügt. :)
cmcromance
Ich kann keinen Fortschrittsbalken sehen, aber ich kann dort Code sehen. :-(
Rajan Rawal
7

Wenn die Webansicht in eine benutzerdefinierte Ansicht eingebettet ist, sodass der Benutzer fast glaubt, eine native Ansicht und keine Webansicht zu sehen, ist es in einem solchen Szenario absurd, den Fehler "Seite konnte nicht geladen werden" anzuzeigen. Was ich normalerweise in einer solchen Situation mache, ist, dass ich eine leere Seite lade und eine Toastnachricht wie unten zeige

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);
            }
        });
Jeevan
quelle
6

Schauen Sie sich die Diskussion bei Android WebView onReceivedError () an . Es ist ziemlich lang, aber der Konsens scheint zu sein, dass a) Sie das Erscheinen der Seite "Webseite nicht verfügbar" nicht stoppen können, aber b) Sie immer eine leere Seite laden können, nachdem Sie einen onReceivedError erhalten haben

Loswerden
quelle
Diese Jungs reden davon, überhaupt onReceivedErrornicht auszulösen. Es wird in meinem Code korrekt ausgelöst, wenn keine Internetverbindung besteht.
JoJo
2

Sie können eine GETAnforderung verwenden, um den Seiteninhalt abzurufen und diese Daten dann mithilfe von anzuzeigen. Auf Webviewdiese Weise verwenden Sie nicht mehrere Serveraufrufe. Alternativ können Sie Javascriptdas DOMObjekt auf Gültigkeit prüfen .

Ravi Vyas
quelle
Das ist eine gute Idee, aber es ist wirklich bedauerlich, dass wir so etwas tun müssen ...
Jeffrey Blattman
2

Vielleicht verstehe ich die Frage falsch, aber es hört sich so an, als würden Sie sagen, dass Sie den Fehler erhalten haben, und Sie fragen sich nur, wie Sie den Fehler am besten nicht anzeigen können. Warum entfernen Sie nicht einfach die Webansicht vom Bildschirm und / oder zeigen eine andere Ansicht darüber an?

Matthew Horst
quelle
2

Hier habe ich die einfachste Lösung gefunden. Schau dir das an..

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

Und hier ist die Methode 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;
}
Ankush Joshi
quelle
1

Ich nehme an, wenn Sie darauf bestehen, können Sie einfach überprüfen, ob die Ressource vorhanden ist, bevor Sie die Funktion loadURL aufrufen. Überschreiben Sie einfach die Funktionen und führen Sie die Überprüfung durch, bevor Sie super () aufrufen.

BEMERKUNG (möglicherweise nicht zum Thema gehörend): In http gibt es eine Methode namens HEAD, die wie folgt beschrieben wird:

Die HEAD-Methode ist identisch mit GET, außer dass der Server in der Antwort KEINEN Nachrichtentext zurückgeben darf

Diese Methode könnte nützlich sein. Wie auch immer Sie es implementieren ... überprüfen Sie diesen Code:

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

Sie können diese Prüfung mit versuchen

if(url.openConnection().getContentLength() > 0)
Sherif elKhatib
quelle
6
Wenn Sie überprüfen, ob die Ressource vorhanden ist, bevor Sie tatsächlich dorthin gehen, wird die Belastung des Servers verdoppelt, da 2 physische Anforderungen pro 1 virtuelle Anforderung vorhanden sind. Dies scheint ein wenig übertrieben.
JoJo
gut verzweifelte Maßnahmen!
Sherif elKhatib
1
Auf jeden Fall könnten Sie es immer noch überladen und den HTML-Inhalt abrufen. Überprüfen Sie, ob ein Fehler vorliegt. Wenn nicht analysieren und anzeigen
Sherif elKhatib
wie würde man das eigentlich umsetzen?
JoJo
@JoJo, tatsächlich reduziert diese Methode die Belastung des Servers im Falle einer ungültigen URL, da das Zurückgeben einer HEAD-Antwort einen weitaus geringeren Overhead hat als das Zurückgeben einer 304- oder 500-Antwort.
Justin Shield
0

Ich würde einfach die Webseite auf das ändern, was Sie zur Fehlerbehandlung verwenden:

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

Dies alles finden Sie unter http://developer.android.com/reference/android/webkit/WebView.html

Ephraim
quelle
0

Ich habe heute an diesem Problem gearbeitet, diese gereizten Google-Fehlerseiten loszuwerden. Es ist mit dem oben gezeigten Android-Beispielcode und in vielen anderen Foren möglich (fragen Sie, woher ich das weiß):

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

WENN Sie es in shouldOverrideUrlLoading () als einen weiteren Webclient einfügen. Zumindest funktioniert dies für mich auf meinem 2.3.6-Gerät. Wir werden später sehen, wo es sonst noch funktioniert. Das würde mich jetzt nur deprimieren, da bin ich mir sicher. Das goBack-Bit gehört mir. Sie können es nicht wollen.

R Earle Harris
quelle
0

Versuche dies

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

Wir können die Sichtbarkeit von webView auf 0 (view.INVISIBLE) setzen und eine Meldung anzeigen. Dieser Code funktioniert für meine App, die auf Lolipop ausgeführt wird.

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

Ich musste mich diesem Problem stellen und habe auch versucht, es aus verschiedenen Perspektiven zu lösen. Schließlich fand ich eine Lösung, indem ich mit einem einzigen Flag überprüfte, ob ein Fehler aufgetreten war.

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

Auf diese Weise verstecke ich die Seite jedes Mal, wenn ein Fehler auftritt, und zeige sie an, wenn die Seite erneut ordnungsgemäß geladen wurde.

Auch eine kleine Verzögerung für den Fall hinzugefügt.

Ich habe die Lösung des Ladens einer leeren Seite vermieden, da Sie später nicht webview.reload () ausführen können, da diese neue Seite im Navigationsverlauf hinzugefügt wird.

Jose M Lechon
quelle
-1

Versuchen Sie dies, sollteOverrideUrlLoading , bevor Sie zu einer anderen URL weiterleiten , um zu überprüfen, ob die Internetverbindung basierend auf dieser Seite geladen ist oder nicht.

Bipin Vayalu
quelle
-1

Überschreiben Sie Ihre WebViewClient-Methode

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

view.loadUrl('about:blank') hat Nebenwirkungen, da das Laden der ursprünglichen URL abgebrochen wird.

duckduckgo
quelle
view.clearView () ist veraltet, siehe stackoverflow.com/questions/3715482/clear-webview-content
silva96