WebView doesn't show content after onPause - android

I have a WebView inside a RecyclerView
I configured the WebViewClient to run onPuase() when page finished loading.
The problem is that some websites (like IMDB) are not viewed, unless I scroll the page down/up, or if the page in stored in cache.
Not working code:
getWebview().setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.onPause();
}
});
If I delay the onPause, it works (delay time differs between different devices)
getWebview().setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(final WebView view, String url) {
super.onPageFinished(view, url);
getWebview().postDelayed(new Runnable() {
#Override
public void run() {
getWebview().onPause();
}
}, 5000);
}
});
I also tried getWebview().postInvalidateDelayed() and getWebview().requestLayout().
Is there anyway to force the webview to display the loaded content, or simulate whatever happens when I scroll the page?
I use Lollipop with Android System WebView 43.0.2357.121

If you try to debug or put some logs in onPagefinshed() method, you will come to know that Webview's onPauuse() will call 2-3 times before site the
loads completely in case of URL redirecting.

Related

Android WebView onPageCommitVisible not fired

I have a WebView, which loads an html page from server, but the page is invisible on the WebView.
The html is loaded properly (I've debugged with chrome://inspect and the html, including all javascripts exist), but it is invisible on the phone screen.
There was no changes in my code, when this bug appeared. The bug appeared when I installed updates to Android System WebView on my phone.
If I uninstall the updates, all works properly again.
In addition, I've checked the callbacks of the WebViewClient and noticed that onPageCommitVisible is not called. So somehow, the page is not loaded properly. Only if I press the Back button, to exit the WebView, I see that the onPageCommitVisible is called for my webpage (buat it doesn't help, as the back button exists the WebView, as expected).
Here is my code for the webview:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RelativeLayout rlMain = new RelativeLayout(getActivity());
rlMain.setContentDescription(Constants.STARTAPP_AD_MAIN_LAYOUT_CONTENT_DESCRIPTION);
rlMain.setId(Constants.MAIN_LAYOUT_ID);
getActivity().setContentView(rlMain);
// Create WebView and set its parameters
try{
webView = new WebView(getActivity().getApplicationContext());
webView.setBackgroundColor(0xFF000000);
getActivity().getWindow().getDecorView().findViewById(android.R.id.content).setBackgroundColor(0x00777777);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient());
// set software acceleration
if (softwareAcceleration) {
ApiUtil.setWebViewLayerTypeSoftware(webView, null);
}
webView.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return true;
}
});
webView.setLongClickable(false);
webView.addJavascriptInterface(createJsInterface(), Constants.INTERFACE);
setWebViewSpecificParameters(webView);
webView.loadDataWithBaseURL("http://www.xxxxxx.com", getHtml(), "text/html", "utf-8", null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
webView.setWebViewClient(new MyWebViewClient());
RelativeLayout.LayoutParams webviewPrms = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT
);
rlMain.addView(webView, webviewPrms);
}
public void setWebViewSpecificParameters(final WebView webView) {
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
}
private class MyWebViewClient extends WebViewClient {
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
Logger.log(TAG, Log.DEBUG, "!!!!!shouldInterceptRequest" );
return super.shouldInterceptRequest(view, url);
}
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
Logger.log(TAG, Log.DEBUG, "!!!!!shouldInterceptRequest" );
return super.shouldInterceptRequest(view, request);
}
#Override
public void onPageFinished(WebView view, String url) {
setWebViewBackground(view);
runJavascript(Constants.JAVASCRIPT_SET_MODE_SERVER, getPosition());
runJavascript(Constants.JAVASCRIPT_ENABLE_SCHEME, "externalLinks");
InterstitialMode.this.onWebviewPageFinished();
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return clicked(url);
}
}
In an app that navigates from one website to another based on user input, there's a high chance (>50%) that the second website won't display at all after calling WebView.loadUrl and the previous website stays visible - it's even interactive, i.e. scrolling works. The problem is usually resolved after calling WebView.loadUrl again. There's no obvious indication of the bug occurring other than the user not seeing the second website. Relying on the user to reload the page manually is not a satisfying solution since the bug occurs quite often.
I was able to workaround this issue by using a custom WebViewClient to detect that the second website was not loaded properly and triggering a reload:
setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
buggyWebViewHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (!wasCommitCalled) {
loadUrl(url);
}
}
}, 2500);
}
}
#Override
public void onPageCommitVisible(WebView view, String url) {
wasCommitCalled = true;
}
});
Where buggyWebViewHandler is a Handler or any other class that allows deferring a piece of code for some time. Additionally, you'll need to set wasCommitCalled = false; whenever WebView.loadUrl is called - for example by overriding the method.
Note that this only works for Android 23 onwards because that's when onPageCommitVisible was added. See here for a full implementation: https://github.com/TomTasche/OpenDocument.droid/blob/8c2eec5c57e5962e9ac4c46549be2241b259eb32/app/src/main/java/at/tomtasche/reader/ui/widget/PageView.java#L72-L96
If anyone is brave enough to dig deeper into why this is happening: while debugging it seemed that onPageStarted is not called whenever this bug occurs. Maybe that helps...

Loading Non cached webview in android app

I have a HTML template file which is used at multiple places one of them is it is used to get loaded as a webview in few android apps, How can I make sure everytime webview is loaded it loads the most recent version(No cache) without making any changes in app settings.
You can try something like this:
WebView webview = new WebView(this);
webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
Check out more here
When WebView finishes a page everytime, clear the cache. Something like this in your WebViewClient:
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.clearCache(true);
}
Just after creating your WebView, before loading any pages, you can clear the cache.
browser.clearCache(true);
and one other way is to Override onPageFinished() which is called each time a page gets loaded, so you could clear cache in it.
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.clearCache(true);
}

How to detect when Android WebView has loaded page?

I have an app that displays a splash page and removed that splash page when a URL is loaded in WebView. The following is the relevant code we are using to remove the splash page:
browser.setWebViewClient(new BrowserClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// Work around for WebView onPageFinished called twice
if (flag == true) {
browser.setVisibility(View.VISIBLE);
splashImage.setVisibility(View.INVISIBLE);
pageLoader.setVisibility(View.INVISIBLE);
} else {
flag = true;
}
}
});
This code works... except it is slow. The splash page takes far too long to remove, long after the webpage has loaded.
Are there any tips on how I can reliably detect when WebView has loaded a page? I've been researching this for the past few days and I can't seem to come up with anything that is reliable.
The most promising I saw is the following, but putting this code throws an error in Android Console:
#Override
public void invalidate() {
super.invalidate();
if (getContentHeight() > 0) {
// WebView has displayed some content and is scrollable.
}
}
Thanks!
EDIT: There are a lot of answers proposing onPageFinished, and even someone marking this as a duplicate with a link to solutions using onPageFinished. Folks, we already are using onPageFinished. We are looking for an alternative to onPageFinished due to how unreliable it is.
If you need than you can achieve this by loaded page progress on using this web client, you can use this also.
webView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
Log.e("progress", ""+progress);
if (progress == 100) { //...page is fully loaded.
// TODO - Add whatever code you need here based on web page load completion...
}
}
});
Xamarin/MAUI solution (see OnPageFinished):
webView.SetWebViewClient(new CustomWebViewClient());
...
public class CustomWebViewClient : WebViewClient
{
public CustomWebViewClient()
{
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
// Your Logic comes here
}
}
You should use WebChromeClient.onProgressChanged() to obtain the current progress of loading a page.
If the splash screen you are using is a simple static image then perhaps you can try the following approach:
In XML nest the splash screen (ImageView) inside the WebView:
<WebView android:id="#+id/wv_your_web_view_id"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView android:id="#+id/iv_your_splash_screen_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#mipmap/img_the_coolest_image_ever"
android:contentDescription="#string/splash_screen_desc"/>
</WebView>
Now for the runtime code:
WebView wvUltimo = findViewById(R.id.wv_your_web_view_id);
wvUltimo.loadUrl(REQUESTED_WEB_PAGE_URL); // e.g. "https://www.google.com"
wvUltimo.getSettings().setJavaScriptEnabled(true); // Only enable this if you need Javascript to work within the WebView!!
wvUltimo.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
// Log.d(TAG + " 185", "Load Status: " + progress);
if (progress == 100) {
ImageView ivCoolSplash = view.findViewById(R.id.iv_your_splash_screen_id);
ivCoolSplash.setVisibility(View.GONE);
}
}
});
...
this guarantees that you have direct access to your splash screen from within your WebView and thus can deactivate or hide it instantly when the web page you requested is ready to be viewed.
This can be done with the use of WebViewClient() to the webview.
Reference : How can I know that my WebView is loaded 100%?

How to make a WebView visible only after it finished displaying content?

I have a webView, where I display a HTML I fetch from the backend.My problem is that I am trying to display a loading message, and show the content only after the page is done.
For doing that, I tried to use onPageFinished, which winda works, but not entirely, because it is called after the data is fetched, but BEFORE the page is displayed, so I'm still displaying a blank screen for about 1 second, before finally displaying the HTML.
From the oficial docs:
public void onPageFinished (WebView view, String url)
Added in API level 1
Notify the host application that a page has finished loading. This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet. To get the notification for the new Picture, use onNewPicture(WebView, Picture).
The problem is that onNewPicture(WebView, Picture) is deprecated
So my question is, is there a way to know when the page is finished, but also fully displayed?
Here is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.messageId = this.getIntent().getStringExtra(ITEM_ID_KEY);
this.setUpActionBar();
this.setContentView(R.layout.activity_inbox_item_detail);
WebView view = (WebView) this.findViewById(R.id.webview);
view.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
view.setVisibility(View.VISIBLE);
}
});
this.fetchInboxDetailsTask(this.messageId);
}
I have a WebView in a fragment and, just for your reference, I have set it up like this.
May be you are missing something. "onPageFinished" works just fine for me.
In onViewCreated method:
mWebView = (WebView) view.findViewById(R.id.appWebView);
mWebView.setWebViewClient(new WebViewClient()
{
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
{
// Handle the error
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url)
{
webViewProgressBar.setVisibility(View.GONE);
super.onPageFinished(view, url);
}
});
and then:
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
mWebView.getSettings().setSupportZoom(true);
mWebView.getSettings().setBuiltInZoomControls(true);
mWebView.loadUrl("http://play.google.com/store/apps/");
You may consider using the Advanced Webview Library for android it provides an interface to reaspond to when page start loading and when finishes! here (AdvancedWebView)

Webview - onPageFinished is not called

In my App i want to cache a webapage in the background with a hidden webview (at the same time another webview is visible to the user and loads another url).
I start the caching in onResume. Here are the code snippets:
1.) onResume:
#Override
public void onResume() {
new LibraryCacher().startCaching(this);
//some more code...
}
2.) LibraryCacher:
public class LibraryCacher extends BasicClass {
public LibraryCacher () {}
public void startCaching(Context context) {
getLogger().debug("startCaching()");
if (NetworkHandler.isOnline(context) == false) {
getLogger().info("We are offline, no caching");
return;
}
final String URL_TO_CACHE = "http://myUrl.com";
WebView w = new WebView(context);
w.setVisibility(View.GONE);
WebSettings webset = w.getSettings();
webset.setJavaScriptEnabled(true);
webset.setDomStorageEnabled(true);
webset.setDatabaseEnabled(true);
webset.setJavaScriptCanOpenWindowsAutomatically(true);
webset.setSupportMultipleWindows(true);
webset.setAppCacheEnabled(true);
webset.setLoadsImagesAutomatically(true);
webset.setAppCachePath(w.getContext().getCacheDir().getAbsolutePath());
webset.setAllowFileAccess(true);
webset.setCacheMode(WebSettings.LOAD_DEFAULT);
w.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
getLogger().debug(url + " caching...");
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
getLogger().debug(url + "cached");
}
});
w.setWebChromeClient(new WebChromeClient());
getLogger().debug("load Url");
w.loadUrl(URL_TO_CACHE);
}
}
At the FIRST-CACHE-TRY (app starts the first time) logcat looks like this:
startCaching()
load Url
http://myUrl.com caching...
After that i put the app in the background and resume it. So, at the SECOND-CACHE-TRY logcat looks like this:
startCaching()
loadUrl
http://myUrl.com caching...
http://myUrl.com cached
My question:
Why doesn't the webview invoke its method onPageFinished at the first try?
EDIT :
It works, if i invoke
new LibraryCacher().startCaching(this);
in onPageFinished of the other webview, which is visible to the user and loads simultaneously another url.
Does anyone know why?
Webviews in android seem to have some shared state. In my case, onPageFinished was never called, because i used:
#Override
public void onPause() {
webView.pauseTimers();
}
On a completely different webview, in a different activity.

Categories

Resources