I have a standard task to display a ListView (UrlListView) with urls. When the user touches the row I open an activity (UrlViewActivity) with WebView. Unfortunately, this trivial task brings many troubles for me in Android...
Standard approach:
- UrlViewActivity has an *.xml file with a layout that contains WebView. When the user touches any row inside UrlListView, I start this activity, set this layout as a content view, find my WebView by id and ask it to load an url. Yes, I also call inside my activity's onPause - mWebView.onPause() and inside onDestroy - mWebView.destroy();
Everything works pretty good until the user tries to open various urls rather often: opens an url, closes UrlViewActivity, opens another url and e t. c...usually after 15-25 such loads (every UrlViewActivity launch creates a new WebView) famous Android 4.4 bug occurs on Moto X and Nexus 5: https://code.google.com/p/android/issues/detail?id=73632 so my app freezes inside nativeLockCanvas...
Then I tried another approach that some guys on StackOverFlow recommended:
- Keeping WebView as a static object, create it only during the first startup and on every UrlViewActivity launch add this WebView and clear its state (and remove this WebView inside onStop() of course).
No freezing!!!
But there is a big problem to clear WebView's state on Android:
- It's really hard to force a WebView correctly measure its height when loading a new url (WebView always tries to remember previous long page and doesn't want to decrease it height even when loading a very small page).
There are many advices to reset WebView's height like the following: How a change the content size of a webview in android? But unfortunately clearView() is already deprecated and does nothing...The only working approach that I found is: calling mWebView.loadUrl("about:blank"); and inside overriden onPageFinished(WebView view, String url) method call mWebView.requestLayout();
That really works and pages become finally take correct height and scrolling works ok, but...it remembers blank page inside its history and shows it to user when he presses back button...
- To resolve the problem of storing blank page in WebView's history I've tried to use clearHistory() method, but...if I call this method inside onPageFinished(WebView view, String url) right after my correct page was loaded guess what? WebView mystically forgets that it has just measured itself correctly (during first onPageFinished(WebView view, String url) call when "about:blank" page was loaded) and shows long scrolling even for a short pages...
Here is my code snippet:
enum WebViewStates {
WEB_VIEW_INITIALIZED, WEB_VIEW_RESET_DONE, WEB_VIEW_HISTORY_CLEARED
}
private ViewGroup mWebViewContainer;
private WebViewStates mWebViewState;
private void setupWebView() {
mScrollView.smoothScrollTo(0, 0);
mWebViewContainer.addView(mWebView);
mWebViewState = WebViewStates.WEB_VIEW_INITIALIZED;
mWebView.loadUrl("about:blank");
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
switch (mWebViewState) {
case WEB_VIEW_INITIALIZED:
mWebViewState = WebViewStates.WEB_VIEW_RESET_DONE;
mWebView.requestLayout();
mWebView.loadUrl(mPreviewUrl);
break;
case WEB_VIEW_RESET_DONE:
mWebViewState = WebViewStates.WEB_VIEW_HISTORY_CLEARED;
mWebView.clearHistory();
break;
case WEB_VIEW_HISTORY_CLEARED:
break;
}
super.onPageFinished(view, url);
}
});
}