1. 程式人生 > >Android webview 關於返回鍵和歷史棧的坑

Android webview 關於返回鍵和歷史棧的坑

最近在做一個webview加載出錯時載入本地的出錯頁,重新整理顯示之前Url的內容。碰到了一連串的坑,同時也瞭解了webview。


            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                super.onReceivedError(view, errorCode, description, failingUrl);
                mFailUrl = failingUrl;
                view.getSettings().setJavaScriptEnabled(true
); view.loadUrl(mErrorWebPage); view.addJavascriptInterface(new LinkInitialize(view), "LinkInitialize"); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

上面程式碼是當加載出錯的時候重寫onreceivedError,在裡面實現載入本地的錯誤頁html。 
然後重點出現了,在點選back按鍵的時候,會出現之前的錯誤頁。也就是說,webview的歷史棧中儲存了錯誤頁的url。所以重寫back事件。

@Override
    public
boolean onKeyDown(int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: WebBackForwardList history = mGachaWebView.copyBackForwardList(); int index = -1
; String url = null; String currentUrl = mGachaWebView.getUrl(); while (mGachaWebView.canGoBackOrForward(index)) { int currentIndex = history.getCurrentIndex(); String lastUrl = history.getItemAtIndex(currentIndex + index).getUrl(); if (!lastUrl.equals(mGachaWebView.getmErrorWebPage()) && !currentUrl.equals(lastUrl)) { mGachaWebView.goBackOrForward(index); url = lastUrl; break; } index--; } if (url == null) { onBackPressed(); } if (history.getSize() == 2 && currentUrl.equals(mGachaWebView.getmErrorWebPage())) { onBackPressed(); } return true; } } return super.onKeyDown(keyCode, event); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

做完這裡的時候,測試大部分頁面,以為已經解決了問題,但是發現,當載入的url存在重定向問題的時候,就導致,始終退不回去了。比如說A->B->Error->B’ 
解釋一下,A頁面點選跳轉到B頁面,但是因為出錯,所以直接跳轉到自定義的Error出錯頁,出錯頁上有個重新整理按鈕,是js呼叫java程式碼,貼一個

@JavascriptInterface
        public void reloadUrl() {
            if(!isDoubleClick()){
                mHandler.post(new Runnable() {
                    public void run() {
                        webView.loadUrl(mFailUrl);
                    }
                });
            }

        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

重新整理按鈕點選後會重新webView.loadUrl(mFailUrl)之前失敗的那個url,這時,因為B是一個重定向的Url,所以webview直接重定向到B’,webview的歷史棧中是這樣的A->B->Error->B’ 
並不是猜想的A->B->Error->B->B’。所以當點選回退按鈕的時候,回到頁面B,重定向到B’,迴圈往復,始終退不出去了。 
在單步除錯的過程中發現,webview中的歷史棧的來源,有兩種,一種是呼叫loadUrl(),會把Url加入到歷史棧中,一種是頁面內點選跳轉,會將點選的那個url加入到歷史棧中。但是有特殊情況,如果load的頁面存在重定向,那麼重定向之前的那個url不會加入到歷史棧中,只會把重定向後的url加入到棧中。

由於重定向導致的無法回退現象,可以在public boolean shouldOverrideUrlLoading(WebView view, String url)解決,

@Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {

                //do what you want 
               return false;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

完成。坑了兩天看這玩意,想過很多方法,比如自己維護一個棧,但是想到重定向的情況,就覺得好不靠譜。