onPageFinished is firing before page is loaded - android

I just want to know when html page is loaded. OnPageFinished is called before whole page is loaded. I got blank view when I set Image View by bitmap created from WebView
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setAlwaysDrawnWithCacheEnabled(true);
mWebView.setWebViewClient(new WebViewClient(){
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon){
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view,String url){
Bitmap b = Bitmap.createBitmap( 480, 240, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
view.draw(c);
mImageView.setImageBitmap(b);
//b.recycle();
}
});
EDIT :
I tried to implement JavaScriptInterface for now only with making Toast message, but it still doesn't work. I've pasted html code and Java :
EDIT :
I finally got it working. I used JavaScriptInterface with proper . When loadUrl is launch html file is being loaded. When whole page is available on screen, onload function from html file call captureImage function from JavaScriptInterface class. Now I have sure that page is fully loaded and I can grab picture of it. Thanks for all help.
CODE:
JAVA :
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setDrawingCacheEnabled(true);
mWebView.addJavascriptInterface(new JavaScriptInterface(this), "Android");
mWebView.setWebViewClient(new WebViewClient(){});
mButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mWebView.loadUrl("file:///android_asset/html_sample.html");
//mWebView.loadUrl("https://www.onet.pl");
}
});
public class JavaScriptInterface {
private Context mContext;;
public JavaScriptInterface(Context context) {
mContext = context;
}
#JavascriptInterface
public void captureImage(){
Bitmap b = mWebView.getDrawingCache(true);
mImageView.setImageBitmap(b);
}
#JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
HTML :
<html>
<head>
<title>My first styled page</title>
<link rel="stylesheet" href="sample_css.css">
</head>
<body onload="function(){ Android.captureImage() }">
...
</body>
</html>

This is because onPageFinished means "the page has finished loading", not "the page is on screen". Unfortunately the WebView doesn't have a 'the page you wanted is now on screen' API. Folks usually resort to a combination of PictureListener (which was deprecated since it's unreliable) and random timeouts (which are either super long or don't work on some devices).
You could try by rendering to a small bitmap and checking if it's all white on every PictureListener callback (and remember to stop doing this when you're done waiting, otherwise you'll burn tons of CPU if the page has animations/gifs/etc..). Rendering to a small bitmap will still be very CPU-intensive if the page has big images, so this is definitely not a great solution.

It happened to me also, that in WebViewClient, the callback onPageFinished kicks in before the actual window.load event.
Still investigating on why this happens sometimes, which is hard because the android app is produced by a heavily customized in-house hybrid app generator.
Nevertheless, I've got past this issue by implementing a safeguard that checks if there is an error in the script that I want to call in onPageFinished, in which case I add an event handler which calls again my script during window.load.
You can also use document.addEventListener("DOMContentLoaded", ...) instead of window.load.
Below is a code snippet that exemplifies this, also with debug.log calls. You can pass the call to your javascript interface as argument
private void executeOnLoad(final WebView view, final String jsStringToExecute) {
StringBuilder sb = new StringBuilder("javascript:");
sb.append("try {console.log('native.onPageFinished. document.readyState: ' + document.readyState);").append(jsStringToExecute).append("} catch(err){console.log('error calling jsBridge script on page load, deferring call to window.load event');")
.append("window.addEventListener('load', function() {console.log('window.onload callled from native. document.readyState: ' + document.readyState);").append(jsStringToExecute).append("});").append("}");
String jsWithWindowLoadedFallback = sb.toString();
view.loadUrl(jsWithWindowLoadedFallback);
}

Found simple technique to load page even after onPageFinished is called--
Recursively call loadUrl method until page is not loaded successfully..
#Override
public void onPageFinished(WebView view, String url) {
// progressDialog.hide();
Log.e("onPageFinished","onPageFinished");
if (view.getContentHeight() == 0){
pbar.setVisibility(View.VISIBLE);
webView.loadUrl("https://drive.google.com/viewerng/viewer?embedded=true&url="+pdf);
}
else {
pbar.setVisibility(View.GONE);
}
}

try this :-
OnClickListener btnGoListener = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
webView00.loadUrl(etUrl.getText().toString());
webView00.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
Toast.makeText(getBaseContext(), "Loading Finished 2", Toast.LENGTH_LONG)
.show();
}
});
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_web_page00);
webView00 = (WebView) findViewById(R.id.webView00);
btnGo = (Button) findViewById(R.id.go_btn);
etUrl = (EditText) findViewById(R.id.url_edittext);
webView00.getSettings().setJavaScriptEnabled(true);
btnGo.setOnClickListener(btnGoListener);
webView00.loadUrl("http://google.com");
//webView00.setWebViewClient(new myWebViewClient());
//webView00.setWebChromeClient(new myWebChromeClient());
webView00.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
Toast.makeText(getBaseContext(), "Loading Finished 1", Toast.LENGTH_LONG)
.show();
}
});
}

Use WebViewClient and onPageFinished method as below:
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
if (!loadingFinished) {
redirect = true;
}
loadingFinished = false;
webView.loadUrl(urlNewString);
return true;
}
#Override
public void onPageStarted(WebView view, String url) {
loadingFinished = false;
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
}
#Override
public void onPageFinished(WebView view, String url) {
if(!redirect){
loadingFinished = true;
}
if(loadingFinished && !redirect){
Bitmap b = Bitmap.createBitmap( 480, 240, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
view.draw(c);
mImageView.setImageBitmap(b);
} else{
redirect = false;
}
}
});
For more information refer https://stackoverflow.com/a/5172952/685240
Hope it helps.
EDIT : As per your comment, I think your page gets loaded successfully but it takes time to render/draw the page on screen, which is the cause of your issue. Try with implementing onPictureListener for webview. For more reference, refer https://stackoverflow.com/a/18123023/685240

Related

Android WebView issue on override url loading

I’m trying to override url loading when clicking on a link on an app WebView.
The page loads but the WebView will keep it’s last scroll position and content size.
Is there some parameter I forgot to set on the WebView to reset the content size and the scroll position on next load?
Here’s how I’m using it:
#SuppressLint("SetJavaScriptEnabled")
#AfterViews
protected void afterViews() {
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebClient());
webView.setWebChromeClient(new ChromeClient());
webView.loadUrl(url);
}
public class WebClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
boolean isValidEmail = url.startsWith("mailto:") && Patterns.EMAIL_ADDRESS.matcher(url.substring("mailto:".length())).matches();
boolean isValidPhone = url.startsWith("tel:") && Patterns.PHONE.matcher(url.substring("tel:".length())).matches();
if (url.startsWith("about:")) {
return super.shouldOverrideUrlLoading(view, url);
}
if (isValidEmail) {
Intent sendIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse(url));
startActivity(Intent.createChooser(sendIntent, ""));
} else {
if (isValidPhone) {
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
startActivity(Intent.createChooser(dialIntent, ""));
} else {
WebViewActivity.this.setPageTitle(url);
webView.loadUrl(url);
}
}
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
//..
}
}
public class ChromeClient extends WebChromeClient {
#Override
public void onProgressChanged(WebView view, int progress) {
//...
}
}
Thanks.
Did you try to set scroll position in onPageFinished?
#Override
public void onPageFinished(WebView view, String url) {
// other code...
view.scrollTo(0,0);
}
That should set WebView content back to top, and not on old scroll position
Edit 1:
Sometimes if the page loads for a long time this won't work properly, so we must wait for page to get fully loaded:
#Override
public void onPageFinished(WebView view, String url) {
view.postDelayed(new Runnable() {
#Override
public void run() {
webView.scrollTo(0, 0);
}
// Delay the scrollTo to make it work
}, 300);
}
Please note that webView this time is not the WebView from the method onPageFinished, but the WebView fetched from the layout (same one as in afterViews() method).
#Bojan Kopanja, my sincere apologies for misleading.
It turns out I had the webview inside a pull to refresh listener with a scrollview and removing that got rid of the problem.
Thanks for your help nevertheless.

onPageFinished method is called BEFORE the website finishes loading?

It seems that I made some inaccuracies or I missed something regarding public class myWebViewClient class and public void onPageFinished(WebView view, String url). Initially and in the beginning I tried to launch www.yahoo.com and after it finishes loading I fire a toast from inside the public void onPageFinished(WebView view, String url) as indication to me the loading of the www.yahoo.com is finished, and up to here every thing is fine. Inside my RelativeLayout I have a button and edittext and my webview is layedout-above them. The purpose of having an edittext is to enable the user to enter their webite and by clicking on go-button, the entered website should be launched and I expect to see the toast I have inside public void onPageFinished(WebView view, String url) is fired again after the new website finishes loading. But what happens is, once the user enters a new website in the edittext field and immediately after they press go_button the toast fires before even the website is loaded and it fires once again after the same web site is finished loading. Actually, I expect the toast to be fired only after every website finishes loading, but what is happening with me is not like that. Please provide me with suggestions to prevent occurring such problem.
JavaCode:
OnClickListener btnGoListener = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
webView00.loadUrl(etUrl.getText().toString());
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_web_page00);
webView00 = (WebView) findViewById(R.id.webView00);
btnGo = (Button) findViewById(R.id.go_btn);
etUrl = (EditText) findViewById(R.id.url_edittext);
webView00.getSettings().setJavaScriptEnabled(true);
webView00.setWebViewClient(new myWebViewClient());
webView00.setWebChromeClient(new myWebChromeClient());
btnGo.setOnClickListener(btnGoListener);
webView00.loadUrl("http://google.com");
}
public class myWebChromeClient extends WebChromeClient {
}
public class myWebViewClient extends WebViewClient {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Toast.makeText(getBaseContext(), "Loading Finished", Toast.LENGTH_LONG)
.show();
}
};
From the documentation :
When onPageFinished() is called, the rendering picture may not be updated yet.
To get the notification for the new Picture, use onNewPicture(WebView, Picture).
http://developer.android.com/reference/android/webkit/WebViewClient.html#onPageFinished(android.webkit.WebView, java.lang.String)
I suggest that you implement method onProgressChanged from WebChromeClient.
Documentation :
http://developer.android.com/reference/android/webkit/WebChromeClient.html#onProgressChanged(android.webkit.WebView, int)
Have not tried the Chrome client yet, so have commented that one out, perhaps you can change seamlessly between them.
Nevertheless, I would think something like this should work:
OnClickListener btnGoListener = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
webView00.loadUrl(etUrl.getText().toString());
webView00.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
Toast.makeText(getBaseContext(), "Loading Finished 2", Toast.LENGTH_LONG)
.show();
}
});
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_web_page00);
webView00 = (WebView) findViewById(R.id.webView00);
btnGo = (Button) findViewById(R.id.go_btn);
etUrl = (EditText) findViewById(R.id.url_edittext);
webView00.getSettings().setJavaScriptEnabled(true);
btnGo.setOnClickListener(btnGoListener);
webView00.loadUrl("http://google.com");
//webView00.setWebViewClient(new myWebViewClient());
//webView00.setWebChromeClient(new myWebChromeClient());
webView00.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
Toast.makeText(getBaseContext(), "Loading Finished 1", Toast.LENGTH_LONG)
.show();
}
});
}
I noticed onPageFinished is sometimes called multiple times if the webview re-rendered a page that was already loaded. On the reload, the webview would first render about:blank and calls onPageFinished before loading the actual webpage and calling onPageFinished again. The sequence is:
load www.google.com
onPageFinished is called
load 'www.google.com' again
onPageFinished is called. The URL is about:blank
onPageFinished is called. The URL is www.google.com
To get around this issue in step 4, you can check that the url parameter passed to onPageFinished is the one you care about:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
webView00.loadUrl(myWebPage);
}
public class myWebViewClient extends WebViewClient {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, URL);
if(url == myWebPage) {
Toast.makeText(getBaseContext(), "Loading Finished", Toast.LENGTH_LONG)
.show();
}
};

Scroll an HTML file right after it loaded

In my app I'm loading a local HTML file to a webview. If some button was clicked, I want to load a local HTML file and scroll it with specific value in y axis.
The problem is that the command:
webview.scrollTo(0, scrollY);
is executed too early, before the HTML file finish loaded, so the scrolling is not happen.
I tried to use a lot of answers from Stackoverflow (like this, and this) but the problem is always the same. I can see in debug mode that the scrollTo command executed before the file is visible.
Anyone have any idea how can I achieved this scrolling?
After trying all the answers I found that only the following really help:
private final Handler mHandler = new Handler();
// in onCreate
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (mWebView.getContentHeight() > 0) {
mWebView.scrollTo(0, mLastPosition);
Log.d("scrolling", "true");
mHandler.removeCallbacks(this);
} else {
mHandler.postDelayed(this, 100);
}
}
}, 100);
This solution was taken from hereenter link description here
WebViewClient will help you. Extend onPageFinished() as follows:
webview.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
webview.scrollTo(0, scrollY);
}
});
fisrt set custom webview client like this
webview.setWebViewClient(new CustomWebViewClient());
then add following piece of code in class
private class CustomWebViewClient extends WebViewClient
{
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
// TODO Auto-generated method stub
return false;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
webview.scrollTo(0, scrollY);
}
}

not able to enter text in webview on nexus 4 android 4.2.2

I am trying to open a webpage inside web view and it is working fine on andoid 4.1.2 and below, but when I tried the same code in android 4.2.2 i.e nexus 4 it is not taking any input from keyboard.
When i click on any edit text on web page keyboard gets open and it also show the focus on edit text, but as soon as I press any character keyboard focus lost from the edit text and nothing gets typed on the field. be low is my code
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setPluginState(PluginState.ON);
mWebView.getSettings().setAllowFileAccess(true);
mWebView.setWebViewClient(new MyWebViewClient());
mWebView.clearHistory();
mWebView.clearFormData();
mWebView.clearCache(true);
mWebView.loadUrl(strUrl);
mWebView.requestFocus();
/**
* webview client
*/
private class MyWebViewClient extends WebViewClient {
#Override
// show the web page in webview but not in web browser
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if ( !getSuceessParams(url) )
view.loadUrl(url);
return true;
}
#Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
handler.proceed("checkin", "4good");
}
#Override
public void onPageFinished(WebView view, String url) {
System.out.println("onPageFinished " + url);
context.removeDialog(0);
super.onPageFinished(view, url);
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
System.out.println("onPageStarted " + url);
Fragment fragment = context.getLastFragment();
if ( fragment.getTag() == "campaign_donation_web_fragment" ) {
CheckinLibraryActivity.strProgressMessage = "Loading..";
context.showDialog(0);
}
super.onPageStarted(view, url, favicon);
}
}
I am getting following error
****Should not happen: no rect-based-test nodes found
Thanks
I had a similar issue and it seemed to be fixed by not using the SwiftKey keyboard instead using the Google keyboard. http://support.swiftkey.net/forums/116693-2-bug-reports/suggestions/3808949-phonegap-app
In my case TabHost from a previous fragment in back stack was stealing the focus on every key press. Here's how I fixed it:
tabHost.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
#Override
public void onViewDetachedFromWindow(View v) {}
#Override
public void onViewAttachedToWindow(View v) {
tabHost.getViewTreeObserver().removeOnTouchModeChangeListener(tabHost);
}
});
See https://code.google.com/p/android/issues/detail?id=2516 for more on the topic.

Trying to display url in Web View

I am experimenting with the loopj package. I am trying to make a HTTP request to a website and display the website in the webview.
I am successfully getting a result back, however the web view does not display the page as desired, instead chrome opens up and displays the page.
Am I missing something or is there a way I can override this unwanted behaviour?
Below is my oncreate method where I am making the request:
public class MainActivity extends Activity {
Button connectBtn;
TextView status;
WebView display;
String url = "http://www.google.com";
AsyncHttpClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
status = (TextView)findViewById(R.id.statusbox);
connectBtn = (Button)findViewById(R.id.connectBtn);
display = (WebView)findViewById(R.id.webView1);
connectBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
client = new AsyncHttpClient();
client.get(url, new AsyncHttpResponseHandler(){
#Override
public void onSuccess(String response) {
Toast.makeText(getApplicationContext(), "Success!", Toast.LENGTH_SHORT).show();
display.loadUrl(url);
}
});
}
});
}
setWebViewClient to your WebView and override shouldOverrideUrlLoading() now write view.loadUrl(url); in that method.
Just add this code,
display.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}});
You need to set a WebViewClient and override the shouldOverrideUrlLoading method. Something like this:
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
view.loadUrl(url);
}
});
That makes sure that clicks on links in the WebView are handled by the WebView itself.
Edit: Actually, I misread the question. You aren't dealing with a click in the WebView itself, so this isn't relevant. Sorry!
just use this code under you webviewclient
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
final EditText editText = (EditText) findViewById(R.id.urlfield);
editText.setText(url);
}
}

Categories

Resources