I have an android application that loads web pages in an activity with a WebView. I am using the retrieving the page manually and using WebView's loadDataWithBaseURL to display it on screen. Everything there is fine.
Now, i am trying to override the Back button press to simulate going back in the WebView history stack. I am able to override the Back button press, i can see that there is a history stack in the WebView, i can see that the history url is correct, but when i call WebView's goBack() method, it displays a blank page.
Anyone encountered this before or give me a couple of suggestions to proceed from this?
Edit: If i use WebView's loadUrl method, the Back button with an override works as intended. But why.... If i need to handle this manually, how do i start messing with history pages?
I got the same problem also. I found that the problem went away if I set the historyUrl parameter on the call to loadDataWithBaseURL.
You should check if the canGoBack() method returns true before calling goBack()
The only solution I've found is to create a Stack<String> and manually manage history
The way I deal with this is keeping a local stack pointer to the number of loaded pages after the root page loaded using loadDataWithBaseURL . When going back, if my pointer hits 1 I am at root level and reload the root page with loadDataWithBaseURL.
FYI, I use this code in Activities with fragments, so the fragments implement the interface IBackButtonListener which helps me to capture the back button in the main activity and propagate the event to the current fragment. If the fragment returns true it means it has taken care of the event.
IBackbuttonListener.java
public interface IBackButtonListener {
public boolean onBackButtonPressed();
}
Fragment that implements IBackButtonListener and has a webview loaded from html data.
private int historyStackPointer = 0;
...
#Override
public boolean onBackButtonPressed() {
boolean rtn = false;
if (webView.canGoBack()) {
if(historyStackPointer > 1) {
webView.goBack();
historyStackPointer--;
rtn = true;
}else{
if(historyStackPointer == 1) {
// Reload the html data
webView.loadDataWithBaseURL("file:///android_asset/", html_data, "text/html", "UTF-8", null);
historyStackPointer = 0;
rtn = true;
}else{
webView.loadUrl("about:blank");
rtn = false;
}
}
} else {
rtn = false;
}
return rtn;
}
html_data is a String with the page's html.
What I noticed is that if the url ends in .html, that white screen appears when back button is pressed.
On the other hand, if you remove that .html from your url - obviously only if this is supported by that website (i.e. the redirection and all is handled properly at the server side and that it doesn't trigger the 404 Page Not Found error), that url will act as your base this time and when you press the back button, that white screen should not appear this time.
for example: you have to replace
http://example.com/page.html to:
http://example.com/page
Related
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);
}
});
}
Is there a way I can have my own history stack for webview?
It sounds to me that webview.canGoBack() similar to stack.peek(), and webview.goBack() similar to stack.pop(). I wanted to have a way to create my own stack that keeps the webview history because I want to add additional info to the stack depends on the page that is currently being viewed, and this stack might have non-url strings. This is why I wanted to create my own custom stack instead of using the native methods.
I tried to create a stack and add piece of info when onPageStarted is called. then I realized there are several redirects happen would cause onPageStarted being called several times within a page.
Let's say I start from pageA -> pageB -> pageC. there are 1 redirect happen on pageA and 2 redirects happen on pageB. what's gonna happen is:
by using webview.goBack(), my page go from pageC -> pageB -> pageA. this is exactly the behavior I want.
but when using my custom stack, my page go from pageC -> pageB -> pageB-> pageB -> pageA -> pageA
is htere a way that I can create a custom stack that has the same behavior as webview.goBack()?
Thanks for your help!
What you need to do is to override the WebViewClient function shouldOverrideUrlLoading which gets called
before a new url is loaded, and which allows you to peek its value. Your implementation can then store all visited urls:
ArrayList<String> visitedUrlStack = new ArrayList<String>();
webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
visitedUrlStack.add(url);
return false; // continue with loading of url!!
}
});
You can interrogate visitedUrlStack at any point in your program for a list of visited urls.
It is important that your implimentation of shouldOverrideUrlLoading() will return false. This implies
to the webview that it can go on loading the url.
I am using a webview to load a remote mobile-optimized webpage (like m.mysite.com). The site uses jquery to load next 10 articles. I mean, by default only 10 articles are visible and on the bottom there is a button "load more". When a user presses it, it loads next 10 articles, and so on.
Now, when I load next 10 articles and want to read 15th or 16th article (just an example), the webview loads the article itself. but when I return via mobile Back button, the webview does not load to 15th or 16th article, but it reloads the page and I find myself on article 1 (e.g. it loads the default URL with first 10 articles only).
I tried this in the PC web browser, and it works fine in such browser.
How can I force webview to load the page from the cache, and not to reload it?
I use the usual code for back button:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the BACK key and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
//gives the same problems
// #Override
// public void onBackPressed() {
// super.onBackPressed();
// webView.goBack();
// }
I found your question here, and saw it has no answer.
I am currently looking for the same thing, and I found this while researching and I am going to try it out: http://alex.tapmania.org/2010/11/html5-cache-android-webview.html
This should enable Cache on your webview. It's a matter of just copy and paste what is on the link above.
If you only want cache in the Back button, probably just keep it disabled and enable it when Back button is pressed?
Hope this helps you.
I've done alot of Googling on this and haven't found an answer. I have a webview as part of an overall layout with other controls. I use the webview to show formatted text (recipe descriptions with bold and italic fonts) and URLs. The URLs point to Youtube and are fully qualified (ie. http://www.youtube.com/watch?v=fyzyhuVgzRE). When I click on the link in my web view, the web view control itself disappears from the layout (leaving the rest of the controls on the page intact) and the default web browser does not launch.
It behaves as if I've set the visibility of the web view to GONE, but I do not manipulate the visibility of any of the controls on the layout.
One interesting clue in the LogCat output is an INFO level message from the OS:
MotionRecognitionManager .unregisterListener : / listener count = 0->0,
listener=android.webkit.ZoomManager$1#41ac2fc0
Any ideas what would cause this behavior?
EDIT
Here is how I setup the webview in the onCreate() method of the activity:
webView1 = (WebView)findViewById(R.id.webView1);
webView1.getSettings().setJavaScriptEnabled(true);
webView1.getSettings().setAllowFileAccess(true);
webView1.setWebViewClient(new MyWebViewClient());
And the MyWebViewClient class:
private class MyWebViewClient extends WebViewClient {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url != null && url.startsWith("http://")) {
view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
} else {
return false;
}
}
}
Oddly enough the shouldOverrideUrlLoading is never called.
Well, I'm a dope. It turns out that the double quotes in the href attribute of the anchor were doubled. My system integrates with a MySQL db over the web and I have to do alot of transformation of data between MySQL/PHP and Android/SQLite. During one of these transformations I double-escaped the quotes in the href. So what should have been:
Link Text
was instead rendered as:
Link Text
In the web view the resulting URL looked fine. It was underscored properly and looked like any other URL. It is odd though that simple doubling the quotes causes the behavior. I'll see if there is a known bug like this for Android. At the very least the WebView should through some kind of exception, not simply disappear from the screen.
I faced this type of behavior when webview tries to load content it cant handle. Intercept ref clicks using WebViewClient and send intent to open this ref in external application. Check this thread.
is there a way to hide or disable the URL field in the locationbar? In my case the device is a tablet run as a kiosk browser, so only one URL is allowed.
I fixed this by changing the code in the ChildBrowser.java to
private void navigate(String url) {
InputMethodManager imm = (InputMethodManager)this.ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
if (!url.startsWith("http")) {
this.webview.loadUrl("http://" + url);
}
this.webview.loadUrl("http://www.my-only-allowed-site.example.org");
this.webview.requestFocus();
}
This works well, but is not nice. You can still see the URL. I´d like to have any of this possible solutions:
1) completely hide the URL field
2) hide the softkeyboard when clicking on the URL field
3) set the URL fonts color to black
Any idea?
thanks in advance
If you modify the source code for the plugin, you can hide the url field and close button by modifying the source code for the plugin and just comment out the following line:
toolbar.addView(back); //shows the back button
toolbar.addView(forward); //shows the forward button
//toolbar.addView(edittext); //shows the URL - comment this line out to hide the URL
toolbar.addView(close); //shows the close button
Edit: oops, I just saw from your comment that you figured this out in the same way!
I don't know anything about Phonegap but I'm assuming you're using a standard Android WebView?
If you're seeing a URL bar then it usually means that the default system browser is being invoked to handle the loading of the page. To prevent this set a WebViewClient as follows...
this.webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
});
The shouldOverrideUrlLoading(...) method is called by the host application to see if it should override the loading by using Activity Manager to find a suitable app (usually the stock browser app). Returning false means the WebView instance wants to handle its own URL loading and you won't see a URL bar at all.
EDIT: If that fixes it but also looses the navigation buttons then I suggest you maintain your own history collection and provide your own buttons for back/forward/exit.