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