android webview client activity indicator - android

I got the code for showing activity indicator in a webview. I checked more than one reference and still I couldn't get it working. Can you please help me to debug my code below?
The activity indicator is not coming with below code
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
final BaseActivity MyActivity = ReviewWebActivity.this;
setContentView(R.layout.review_web);
getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
Window.PROGRESS_VISIBILITY_ON);
ScannedProduct product = getReviewUrl();
reviewUrl = product.getReviewLink();
if (reviewUrl == null) {
String err = product.getErrorCode();
if(err.equals("")) err ="No Data Available for this product";
Toast.makeText(getApplicationContext(),
"No Data Available for this product", 1).show();
return;
}
webReview = (WebView) findViewById(R.id.webReview);
webReview.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
// Make the bar disappear after URL is loaded, and changes
// string to Loading...
MyActivity.setTitle("Loading...");
MyActivity.setProgress(progress * 1000); // tried with 100 also
}
});
webReview.setWebViewClient(new ReviewWebClient());
webReview.getSettings().setJavaScriptEnabled(true);
webReview.loadUrl(reviewUrl);
}

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class SandbarinFacebook extends Activity {
WebView mWebView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ProgressDialog pd = ProgressDialog.show(this, "", "Loading...",true);
mWebView = (WebView) findViewById(R.id.webkitWebView1);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setSupportZoom(true);
mWebView.getSettings().setBuiltInZoomControls(true);
mWebView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
if(pd!=null && pd.isShowing())
{
pd.dismiss();
}
}
});
mWebView.loadUrl("http://www.yahoo.co.in");
setTitle("Yahoo!");
}
}

Write below code in Activity's onCreate method.
webView.setWebChromeClient(new ChromeClient());
progress=ProgressDialog.show(this, "", "Loading...");
webView.loadUrl(url);
Create ChromeClient class in same activity.
private class ChromeClient extends WebChromeClient {
#Override
public void onProgressChanged(WebView view, int newProgress) {
if(newProgress >= 85) {
progress.dismiss();
}
super.onProgressChanged(view, newProgress);
}
}
Declare objects accordingly. Get back to me If you still face error. I will provide full source code.

I cannot post a comment because I don't have enough reputation points, but just a quick comment on the accepted answer: Check for null before checking if the dialog is showing. This will avoid the dreaded NPE.
if(pd != null && pd.isShowing()) { ... }

Kotlin snipet:
myProgressBar.show()
myWebView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
myProgressBar.hide()
}
}
Add this extension functions to your extensions file:
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.GONE
}

Related

Android WebView not stopping after user presses back

I am playing a YouTube video inside a WebView. I am able to play it, but when the person leaves the screen, I am not able to stop the audio from playing.
I tried various things inside onDestroy and onPause, or taking them out entirely, but they didn't seem to make a difference.
Would anyone know why the audio keeps playing and doesn't stop even after the app is turned off and the user opens other apps?
Here is my code for the whole class:
import com.flurry.android.FlurryAgent;
import utils.SendEmail;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebSettings.PluginState;
import android.widget.Button;
public class YoutubeActivity extends Activity
{
WebView webview = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
webview = new WebView(this);
setContentView(webview);
webview.getSettings().setAppCacheEnabled(false);
webview.getSettings().setJavaScriptEnabled(true);
webview.setInitialScale(1);
webview.getSettings().setPluginState(PluginState.ON);
WebSettings webSettings = webview.getSettings();
webSettings.setLoadsImagesAutomatically(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setUseWideViewPort(true);
webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return false;
}
});
webview.setWebChromeClient(new WebChromeClient(){});
webSettings.setDomStorageEnabled(true);
webSettings.setAppCacheEnabled(true);
webSettings.setAppCachePath(getApplicationContext().getFilesDir().getAbsolutePath() + "/cache");
webSettings.setDatabaseEnabled(true);
webSettings.setDatabasePath(getApplicationContext().getFilesDir().getAbsolutePath() + "/databases");
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences( YoutubeActivity.this);
String url_to_watch = prefs.getString( "url_to_watch" , null );
webview.loadUrl(url_to_watch);
}
#Override
public void onPause()
{
super.onPause();
try
{
if ( webview != null )
{
webview.clearCache(true);
webview.getSettings().setAppCacheEnabled(false);
webview.stopLoading();
webview.destroy();
sendEmail ("in pause " , "");
webview = new WebView(this);
}
this.finish();
}
catch ( Exception e )
{
}
}
#Override
public void onDestroy()
{
super.onDestroy();
try
{
if ( webview != null )
{
webview = new WebView(this); // To try to reset the webview - didn't work.
}
}
catch ( Exception e )
{
}
}
#Override
public void onStop()
{
super.onStop();
FlurryAgent.onEndSession(this);
try
{
if ( webview != null )
{
webview.clearView();
webview.getSettings().setAppCacheEnabled(false);
webview.stopLoading();
webview.destroy();
sendEmail ("in stop " , "");
}
}
catch ( Exception e )
{
}
this.finish();
}
#Override
protected void onResume()
{
super.onResume();
try
{
webview.onResume();
}
catch ( Exception e )
{
}
}
#Override
protected void onRestart()
{
super.onRestart();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack())
{
webview.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
// Subject , body
public void sendEmail( String subject , String body )
{
String[] params = new String[] { "http://www.problemio.com/problems/send_email_mobile.php", subject, body };
SendEmail task = new SendEmail();
task.execute(params);
}
//#Override
public void onPageFinished(WebView view, String url)
{
//super.onPageFinished(view, url);
view.clearCache(true);
}
public void onBackPressed ( )
{
final AlertDialog.Builder linkedin_builder = new AlertDialog.Builder(this);
linkedin_builder.setMessage("" +
"Go back to the home screen?")
.setCancelable(false)
.setNegativeButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id)
{
if ( webview != null )
{
webview.destroy();
}
Intent myIntent = new Intent(YoutubeActivity.this, MainActivity.class);
YoutubeActivity.this.startActivity(myIntent);
}
})
.setPositiveButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id)
{
dialog.cancel();
}
})
;
AlertDialog alert = linkedin_builder.create();
alert.show();
}
#Override
protected void onStart()
{
super.onStart();
FlurryAgent.onStartSession(this, "4VYNFK3V6RCZ53CZ3J32");
}
}
Any thoughts on what might stop the audio from playing and what may be causing it?
Thank you!
try this, hope it helps:
#Override
public void onPause() {
myWebView.onPause();
myWebView.pauseTimers();//this may cause adMob to stop working
super.onPause();
}
#Override
public void onResume() {
super.onResume();
myWebView.resumeTimers();
myWebView.onResume();
}
#Override
protected void onDestroy() {
myWebView.destroy();
myWebView = null;
super.onDestroy();
}
You should call:
webView.loadUrl("about:blank");
It will destroy all audio/video as well as Javasript objects and stop all running functions on webview
Taken from https://stackoverflow.com/a/17690221/3032209:
You should call through to the WebView's onPause() and onResume() from your Activity's onPause() and onResume(), respectively.
Pauses any extra processing associated with this WebView and its
associated DOM, plugins, JavaScript etc. For example, if this WebView
is taken offscreen, this could be called to reduce unnecessary CPU or
network traffic. When this WebView is again "active", call onResume().
Nothing worked for me in some or all devices. This is the exact solution I guess. Worked for me well.
How to stop youtube video playing in Android webview?
alternatively for API >= 11 you can use
_webview.onPause(); on the activity's / fragment's onPause
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
_webview.onPause();
}
In activity's onDestroy() do:
#Override
protected void onDestroy() {
super.onDestroy();
webView.destroy();
}
You can do it using the method onPause() of your Activity :
#override
public void onPause() {
super.onPause();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
webview.onPause();
}
}
adding a validation for use in API >= 11 (Honeycomb)
private void destroyWebView() {
if (webView != null) {
webView.clearHistory();
webView.clearCache(false);
webView.loadUrl("about:blank");
webView.onPause();
webView.removeAllViews();
// webView.destroyDrawingCache();
// NOTE: This pauses JavaScript execution for ALL WebViews,
// do not use if you have other WebViews still alive.
// If you create another WebView after calling this,
// make sure to call mWebView.resumeTimers().
// webView.pauseTimers();//adMob will fail to load if called
webView.destroy();
webView = null;
}
}

Adding a Progress Dialog in a webview

I have been trying to incorporate a progress dialog into my app when pages are loading in the webview so there isn't just a blank white screen. I know this question is posted everywhere but I can't seem to figure out anything that works for me. I am new to programming and working with android so any information would be helpful. Below is the code that I currently have now. With the onPageStarted I am getting a compile error for Bitmap and I'm not sure what the problem is. Thanks.
public class Grades extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//requesting system settings
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().requestFeature( Window.FEATURE_PROGRESS);
WebView webview = new WebView(this);
//web settings
WebSettings webSettings = webview.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDisplayZoomControls(true);
webSettings.setBuiltInZoomControls(true);
setContentView(webview);
//loads webpages in webview instead of launching browser
webview.setWebViewClient(new WebViewClient() {
ProgressDialog prDialog;
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
prDialog = ProgressDialog.show(Grades.this, null, "loading, please wait...");
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
prDialog.dismiss();
super.onPageFinished(view, url);
}
});
//loading webpage
webview.loadUrl("page__link");
}
Check this code,
final ProgressDialog pd = ProgressDialog.show(OnlinePaymentActivity.this, "", "Please wait, your transaction is being processed...", true);
WebView mWebview = (WebView)findViewById(R.id.webView1);
mWebview.getSettings().setJavaScriptEnabled(true); // enable javascript
mWebview.getSettings().setLoadWithOverviewMode(true);
mWebview.getSettings().setUseWideViewPort(true);
mWebview.getSettings().setBuiltInZoomControls(true);
mWebview.setWebViewClient(new WebViewClient() {
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(activity, description, Toast.LENGTH_SHORT).show();
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
pd.show();
}
#Override
public void onPageFinished(WebView view, String url) {
pd.dismiss();
String webUrl = mWebview.getUrl();
}
});
mWebview .loadUrl("www.google.com");
Webview with progress dialog working for me. full working code
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.yubrajpoudel.R;
/**
* Created by yubraj on 12/25/15.
*/
public class NewsActivity extends AppCompatActivity {
private WebView webView;
ProgressDialog prDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page_news);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
webView = (WebView) findViewById(R.id.wv_news);
webView.setWebViewClient(new MyWebViewClient());
String url = "http://google.com/";
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webView.loadUrl(url);
}
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
prDialog = new ProgressDialog(NewsActivity.this);
prDialog.setMessage("Please wait ...");
prDialog.show();
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if(prDialog!=null){
prDialog.dismiss();
}
}
}
}
Try this and I hope, this is what you are after
webview.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
//Also you can show the progress percentage using integer value 'progress'
if(!prDialog.isShowing()){
prDialog = ProgressDialog.show(Grades.this, null, "loading, please wait...");
}
if (progress == 100&&prDialog.isShowing()) {
prDialog.dismiss();
}
}
});
Kotlin web view with progress dialog working for me. full working code
var webView = web_view_privacy_policy
webView?.settings?.javaScriptEnabled = true
webView?.settings?.loadWithOverviewMode = true
webView?.settings?.useWideViewPort= true
webView.webViewClient = object : WebViewClient(){
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
showProgress(getString(R.string.please_wait))
}
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return true
}
override fun onPageFinished(view: WebView?, url: String?) {
hideProgress()
}
}
webView.loadUrl(ApiEndPoint.ENDPOINT_PRIVACY_POLICY)
web_view_privacy_policy is id of WebView in .xml

How I get page source from WebView?

How I get the web page's source from WebView?
I want to only enter www.google.com in my webview and When I entered this site, I want to get the source for example
String a=........;(source)
I am not sure how far this is going to be helpful. But I have used the below snippet to fetch a small html page's data. I hope it helps you.
Create a class like the one below,
class MyJavaScriptInterface
{
#SuppressWarnings("unused")
public void processHTML(final String html)
{
Log.i("processed html",html);
Thread OauthFetcher=new Thread(new Runnable() {
#Override
public void run() {
String oAuthDetails=null;
oAuthDetails=Html.fromHtml(html).toString();
Log.i("oAuthDetails",oAuthDetails);
}
});OauthFetcher.start();
}
}
Now in your onCreate(),
webview.getSettings().setJavaScriptEnabled(true);
webview.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");
webview.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, final String url) {
String oAuthUrl=getString("www.google.com");
if(url.contains(oAuthUrl))
{
Log.i("Contains","Auth URL");
twitter_webview.loadUrl("javascript:window.HTMLOUT.processHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
}
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
progressDialog.show();
}
});
And now what happens is that, when your page finishes loading, the JavaScript class will be called, which would retrieve the page source and store it in a String as your requirement.
And For API 17
import android.webkit.JavascriptInterface;
public class MainActivity extends Activity {
final Context myApp = this;
#JavascriptInterface
public void processHTML(String html) {
if (html == null)
return;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WebView browser = (WebView) findViewById(R.id.webview);
browser.getSettings().setJavaScriptEnabled(true);
browser.addJavascriptInterface(this, "HTMLOUT");
browser.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
browser.loadUrl("javascript:window.HTMLOUT.processHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
}
});
browser.loadUrl("http://www.google.co.il");
}
}
If your minSdkVersion is 19 or greater you can use the following.
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
view?.evaluateJavascript("""(function() {
return "<html>" + document.getElementsByTagName('html')[0].innerHTML + "</html>";
})()""".trimMargin()) {
console.log(it)
}
}

how to show progress bar on webview?

I am trying to open a webpage in my application using WebView. When I open webpage it shows me blank screen for a while and then open that page in browser inside my application.
Anyone suggest me how to show progress or get rid of that blank screen which comes during loading of webview?
I am using following code:
WebView mWebView = (WebView) findViewById(R.id.mywebview);
mWebView.getSettings().setJavaScriptEnabled(true);
// error handling
final Activity activity = this;
mWebView.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
}
});
// error handling
mWebView.loadUrl(URL);
mWebView.setWebViewClient(new HelloWebViewClient());
Try this:
getWindow().requestFeature(Window.FEATURE_PROGRESS);
WebView mWebView = (WebView) findViewById(R.id.mywebview);
mWebView.getSettings().setJavaScriptEnabled(true);
final Activity activity = this;
mWebView.setWebChromeClient(new WebChromeClient(){
public void onProgressChanged(WebView view, int progress) {
activity.setTitle("Loading...");
activity.setProgress(progress * 100);
if(progress == 100)
activity.setTitle("My title");
}
});
mWebView.loadUrl(URL);
Here is the code that I am using:
Inside WebViewClient:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
findViewById(R.id.progress1).setVisibility(View.VISIBLE);
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
findViewById(R.id.progress1).setVisibility(View.GONE);
}
});
Here is the XML :
<ProgressBar
android:id="#+id/progress1"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Hope this helps..
You need to do something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_PROGRESS);
this.setProgressBarVisibility(true);
}
And then
final Activity activity = this;
mWebView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
activity.setProgress(progress * 100);
}
});
Update
I know it is a bit too late but I have little side note: you shouldn't use setWebViewClient() twice. Second call cancels the first call so you wouldn't get error handling.
1. In oncreate ur call AsyncTask.
2. In asynctask u just make progress dialog and show progress dialog.
3. In webview client u just show again progress dialog click on any link of web site which open in ur webview and after complete load link we override method onPageFinished and in this method we dismiss the progress dialog.
oncreate
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.web_view);
web_view = (WebView) findViewById(R.id.web_view);
OpenWebSiteInWebView opensite = new OpenWebSiteInWebView();
opensite.execute();
}
AsyncTask
private class OpenWebSiteInWebView extends AsyncTask<String, Void, String> {
#SuppressWarnings("deprecation")
#SuppressLint("SetJavaScriptEnabled")
#Override
protected String doInBackground(String... params) {
web_view.setWebViewClient(new MyWebViewClient());
web_view.loadUrl("ur site name");
return null;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(SiteOpenInWebView.this);
pd.setMessage("Please wait Loading...");
pd.show();
}
}
WebViewClient
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
if (!pd.isShowing()) {
pd.show();
}
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
System.out.println("on finish");
if (pd.isShowing()) {
pd.dismiss();
}
}
}
Here is the code I'm using in KOTLIN:
private fun setupWebView() {
val webViewClient: WebViewClient = object: WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
view?.loadUrl(request?.url.toString())
return super.shouldOverrideUrlLoading(view, request)
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
showProgressDialog()
super.onPageStarted(view, url, favicon)
}
override fun onPageFinished(view: WebView?, url: String?) {
hideProgressDialog()
super.onPageFinished(view, url)
}
}
webView.webViewClient = webViewClient
webView.settings.javaScriptEnabled = true
webView.settings.defaultTextEncodingName = "utf-8"
}

How to listen for a WebView finishing loading a URL?

I have a WebView that is loading a page from the Internet. I want to show a ProgressBar until the loading is complete.
How do I listen for the completion of page loading of a WebView?
Extend WebViewClient and call onPageFinished() as follows:
mWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// do your stuff here
}
});
#ian this is not 100% accurate. If you have several iframes in a page you will have multiple onPageFinished (and onPageStarted). And if you have several redirects it may also fail. This approach solves (almost) all the problems:
boolean loadingFinished = true;
boolean redirect = false;
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;
//HIDE LOADING IT HAS FINISHED
} else {
redirect = false;
}
}
});
UPDATE:
According to the documentation:
onPageStarted will NOT be called when the contents of an embedded frame changes, i.e. clicking a link whose target is an iframe.
I found a specific case like that on Twitter where only a pageFinished was called and messed the logic a bit. To solve that I added a scheduled task to remove loading after X seconds. This is not needed in all the other cases.
UPDATE 2:
Now with current Android WebView implementation:
boolean loadingFinished = true;
boolean redirect = false;
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(
WebView view, WebResourceRequest request) {
if (!loadingFinished) {
redirect = true;
}
loadingFinished = false;
webView.loadUrl(request.getUrl().toString());
return true;
}
#Override
public void onPageStarted(
WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
loadingFinished = false;
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
}
#Override
public void onPageFinished(WebView view, String url) {
if (!redirect) {
loadingFinished = true;
//HIDE LOADING IT HAS FINISHED
} else {
redirect = false;
}
}
});
I am pretty partial to #NeTeInStEiN (and #polen) solution but would have implemented it with a counter instead of multiple booleans or state watchers (just another flavor but I thought might share). It does have a JS nuance about it but I feel the logic is a little easier to understand.
private void setupWebViewClient() {
webView.setWebViewClient(new WebViewClient() {
private int running = 0; // Could be public if you want a timer to check.
#Override
public boolean shouldOverrideUrlLoading(WebView webView, String urlNewString) {
running++;
webView.loadUrl(urlNewString);
return true;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
running = Math.max(running, 1); // First request move it to 1.
}
#Override
public void onPageFinished(WebView view, String url) {
if(--running == 0) { // just "running--;" if you add a timer.
// TODO: finished... if you want to fire a method.
}
}
});
}
I found one elegant solution as well, have not tested it rigorously though:
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (webView.getProgress() == 100) {
progressBar.setVisibility(View.GONE);
webView.setVisibility(View.VISIBLE);
}
}
If you want show a progress bar you need to listen for a progress change event, not just for the completion of page:
mWebView.setWebChromeClient(new WebChromeClient(){
#Override
public void onProgressChanged(WebView view, int newProgress) {
//change your progress bar
}
});
BTW if you want display just an Indeterminate ProgressBar overriding the method onPageFinished is enough
I have simplified NeTeInStEiN's code to be like this:
mWebView.setWebViewClient(new WebViewClient() {
private int webViewPreviousState;
private final int PAGE_STARTED = 0x1;
private final int PAGE_REDIRECTED = 0x2;
#Override
public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
webViewPreviousState = PAGE_REDIRECTED;
mWebView.loadUrl(urlNewString);
return true;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
webViewPreviousState = PAGE_STARTED;
if (dialog == null || !dialog.isShowing())
dialog = ProgressDialog.show(WebViewActivity.this, "", getString(R.string.loadingMessege), true, true,
new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// do something
}
});
}
#Override
public void onPageFinished(WebView view, String url) {
if (webViewPreviousState == PAGE_STARTED) {
dialog.dismiss();
dialog = null;
}
}
});
It is easy to understand, OnPageFinished if the previous callback is on onPageStarted, so the page is completely loaded.
for Kotlin users:
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
// do your logic
}
}
there are a lot of methods that you can override though
Use setWebViewClient() and override onPageFinished()
You can trace the Progress Staus by the getProgress method in webview class.
Initialize the progress status
private int mProgressStatus = 0;
then the AsyncTask for loading like this:
private class Task_News_ArticleView extends AsyncTask<Void, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(
your_class.this);
// can use UI thread here
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.setCancelable(false);
this.dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
try {
while (mProgressStatus < 100) {
mProgressStatus = webview.getProgress();
}
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(Void result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
}
}
thanks for the answers. It helped me, but I had to improve it a bit for my needs. I had several pagestarts and finishes so I added a timer which checks if atfer the pagefinish is started a new pagestart. Okay, bad explanation. See the code :)
myWebView.setWebViewClient(new WebViewClient() {
boolean loadingFinished = true;
boolean redirect = false;
long last_page_start;
long now;
// Load the url
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (!loadingFinished) {
redirect = true;
}
loadingFinished = false;
view.loadUrl(url);
return false;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.i("p","pagestart");
loadingFinished = false;
last_page_start = System.nanoTime();
show_splash();
}
// When finish loading page
public void onPageFinished(WebView view, String url) {
Log.i("p","pagefinish");
if(!redirect){
loadingFinished = true;
}
//call remove_splash in 500 miSec
if(loadingFinished && !redirect){
now = System.nanoTime();
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
remove_splash();
}
},
500);
} else{
redirect = false;
}
}
private void show_splash() {
if(myWebView.getVisibility() == View.VISIBLE) {
myWebView.setVisibility(View.GONE);
myWebView_splash.setVisibility(View.VISIBLE);
}
}
//if a new "page start" was fired dont remove splash screen
private void remove_splash() {
if (last_page_start < now) {
myWebView.setVisibility(View.VISIBLE);
myWebView_splash.setVisibility(View.GONE);
}
}
});
Here's a novel method for detected when a URL has loaded by utilising Android's capability for JavaScript hooks. Using this pattern, we exploit JavaScript's knowledge of the document's state to generate a native method call within the Android runtime. These JavaScript-accessible calls can be made using the #JavaScriptInterface annotation.
This implementation requires that we call setJavaScriptEnabled(true) on the WebView's settings, so it might not be suitable depending on your application's requirements, e.g. security concerns.
src/io/github/cawfree/webviewcallback/MainActivity.java (Jelly Bean, API Level 16)
package io.github.cawfree.webviewcallback;
/**
* Created by Alex Thomas (#Cawfree), 30/03/2017.
**/
import android.net.http.SslError;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
/** An Activity demonstrating how to introduce a callback mechanism into Android's WebView. */
public class MainActivity extends AppCompatActivity {
/* Static Declarations. */
private static final String HOOK_JS = "Android";
private static final String URL_TEST = "http://www.zonal.co.uk/";
private static final String URL_PREPARE_WEBVIEW = "";
/* Member Variables. */
private WebView mWebView = null;
/** Create the Activity. */
#Override protected final void onCreate(final Bundle pSavedInstanceState) {
// Initialize the parent definition.
super.onCreate(pSavedInstanceState);
// Set the Content View.
this.setContentView(R.layout.activity_main);
// Fetch the WebView.
this.mWebView = (WebView)this.findViewById(R.id.webView);
// Enable JavaScript.
this.getWebView().getSettings().setJavaScriptEnabled(true);
// Define the custom WebClient. (Here I'm just suppressing security errors, since older Android devices struggle with TLS.)
this.getWebView().setWebViewClient(new WebViewClient() { #Override public final void onReceivedSslError(final WebView pWebView, final SslErrorHandler pSslErrorHandler, final SslError pSslError) { pSslErrorHandler.proceed(); } });
// Define the WebView JavaScript hook.
this.getWebView().addJavascriptInterface(this, MainActivity.HOOK_JS);
// Make this initial call to prepare JavaScript execution.
this.getWebView().loadUrl(MainActivity.URL_PREPARE_WEBVIEW);
}
/** When the Activity is Resumed. */
#Override protected final void onPostResume() {
// Handle as usual.
super.onPostResume();
// Load the URL as usual.
this.getWebView().loadUrl(MainActivity.URL_TEST);
// Use JavaScript to embed a hook to Android's MainActivity. (The onExportPageLoaded() function implements the callback, whilst we add some tests for the state of the WebPage so as to infer when to export the event.)
this.getWebView().loadUrl("javascript:" + "function onExportPageLoaded() { " + MainActivity.HOOK_JS + ".onPageLoaded(); }" + "if(document.readyState === 'complete') { onExportPageLoaded(); } else { window.addEventListener('onload', function () { onExportPageLoaded(); }, false); }");
}
/** Javascript-accessible callback for declaring when a page has loaded. */
#JavascriptInterface #SuppressWarnings("unused") public final void onPageLoaded() {
// Display the Message.
Toast.makeText(this, "Page has loaded!", Toast.LENGTH_SHORT).show();
}
/* Getters. */
public final WebView getWebView() {
return this.mWebView;
}
}
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<WebView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
Essentially, we're appending an additional JavaScript function that is used to test the state of the document. If it's loaded, we launch a custom onPageLoaded() event in Android's MainActivity; otherwise, we register an event listener that updates Android once the page is ready, using window.addEventListener('onload', ...);.
Since we're appending this script after the call to this.getWebView().loadURL("") has been made, it's probable that we don't need to 'listen' for the events at all, since we only get a chance to append the JavaScript hook by making a successive call to loadURL, once the page has already been loaded.
Just to show progress bar, "onPageStarted" and "onPageFinished" methods are enough; but if you want to have an "is_loading" flag (along with page redirects, ...), this methods may executed with non-sequencing, like "onPageStarted > onPageStarted > onPageFinished > onPageFinished" queue.
But with my short test (test it yourself.), "onProgressChanged" method values queue is "0-100 > 0-100 > 0-100 > ..."
private boolean is_loading = false;
webView.setWebChromeClient(new MyWebChromeClient(context));
private final class MyWebChromeClient extends WebChromeClient{
#Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress == 0){
is_loading = true;
} else if (newProgress == 100){
is_loading = false;
}
super.onProgressChanged(view, newProgress);
}
}
Also set "is_loading = false" on activity close, if it is a static variable because activity can be finished before page finish.
The renderer will not finish rendering when the OnPageFinshed method is called or the progress reaches 100% so both methods don't guarantee you that the view was completely rendered.
But you can figure out from OnLoadResource method what has been already rendered and what is still rendering. And this method gets called several times.
#Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
// Log and see all the urls and know exactly what is being rendered and visible. If you wanna know when the entire page is completely rendered, find the last url from log and check it with if clause and implement your logic there.
if (url.contains("assets/loginpage/img/ui/forms/")) {
// loginpage is rendered and visible now.
// your logic here.
}
}
this will been called before he start loading the page
(and get the same parameters as onFinished())
#Override
public void onPageCommitVisible(WebView view, String url) {
super.onPageCommitVisible(view, url);
}
Loading url with SwipeRefreshLayout and ProgressBar:
UrlPageActivity.java:
WebView webView;
SwipeRefreshLayout _swipe_procesbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_url_page);
String url = "http://stackoverflow.com/";
_swipe_procesbar = (SwipeRefreshLayout)findViewById(R.id.url_path_swipe_procesbar);
_swipe_procesbar.post(new Runnable() {
#Override
public void run() {
_swipe_procesbar.setRefreshing(true);
}
}
);
webView = (WebView) findViewById(R.id.url_page_web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
_swipe_procesbar.setRefreshing(false);
_swipe_procesbar.setEnabled(false);
}
});
webView.loadUrl(url);
}
activity_url_page.xml:
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/url_path_swipe_procesbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.test.test1.UrlPageActivity">
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/url_page_web_view" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
Here's a method which allows you to register a Runnable to be executed once a particular web address has finished loading. We associate each Runnable with a corresponding URL String in a Map, and we use the WebView's getOriginalUrl() method to choose the appropriate callback.
package io.github.cawfree.webviewcallback;
/**
* Created by Alex Thomas (#Cawfree), 30/03/2017.
**/
import android.net.http.SslError;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.util.HashMap;
import java.util.Map;
/** An Activity demonstrating how to introduce a callback mechanism into Android's WebView. */
public class MainActivity extends AppCompatActivity {
/* Member Variables. */
private WebView mWebView;
private Map<String, Runnable> mCallbackMap;
/** Create the Activity. */
#Override protected final void onCreate(final Bundle pSavedInstanceState) {
// Initialize the parent definition.
super.onCreate(pSavedInstanceState);
// Set the Content View.
this.setContentView(R.layout.activity_main);
// Fetch the WebView.
this.mWebView = (WebView)this.findViewById(R.id.webView);
this.mCallbackMap = new HashMap<>();
// Define the custom WebClient. (Here I'm just suppressing security errors, since older Android devices struggle with TLS.)
this.getWebView().setWebViewClient(new WebViewClient() {
/** Handle when a request has been launched. */
#Override public final void onPageFinished(final WebView pWebView, final String pUrl) {
// Determine whether we're allowed to process the Runnable; if the page hadn't been redirected, or if we've finished redirection.
if(pUrl.equals(pWebView.getOriginalUrl())) {
// Fetch the Runnable for the OriginalUrl.
final Runnable lRunnable = getCallbackMap().get(pWebView.getOriginalUrl());
// Is it valid?
if(lRunnable != null) { lRunnable.run(); }
}
// Handle as usual.
super.onPageFinished(pWebView, pUrl);
}
/** Ensure we handle SSL state properly. */
#Override public final void onReceivedSslError(final WebView pWebView, final SslErrorHandler pSslErrorHandler, final SslError pSslError) { pSslErrorHandler.proceed(); }
});
// Assert that we wish to visit Zonal's website.
this.getWebView().loadUrl("http://www.zonal.co.uk/");
// Align a Callback for Zonal; this will be serviced once the page has loaded.
this.getCallbackMap().put("http://www.zonal.co.uk/", new Runnable() { #Override public void run() { /* Do something. */ } });
}
/* Getters. */
public final WebView getWebView() {
return this.mWebView;
}
private final Map<String, Runnable> getCallbackMap() {
return this.mCallbackMap;
}
}
Use this it should help.`var currentUrl = "google.com"
var partOfUrl = currentUrl.substring(0, currentUrl.length-2)
webView.setWebViewClient(object: WebViewClient() {
override fun onLoadResource(WebView view, String url) {
//call loadUrl() method here
// also check if url contains partOfUrl, if not load it differently.
if(url.contains(partOfUrl, true)) {
//it should work if you reach inside this if scope.
} else if(!(currentUrl.startWith("w", true))) {
webView.loadurl("www.$currentUrl")
} else if(!(currentUrl.startWith("h", true))) {
webView.loadurl("https://$currentUrl")
} else { ...}
}
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
// you can call again loadUrl from here too if there is any error.
}
//You should also override other override method for error such as onReceiveError to see how all these methods are called one after another and how they behave while debugging with break point.
}
`
Kotlin solution
First Solution is create webviewclient as private class and it is more efficient.
In the other hand second soltion is sorter :)
First Solution
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val webView : WebView = findViewById(R.id.webView)
webView.webViewClient = MyWebViewClient()
}
private class MyWebViewClient : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
println("Load Started")
}
override fun onPageFinished(view: WebView, url: String) {
println("Load Finished")
}
}
}
Second Solution
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val webView : WebView = findViewById(R.id.webView)
webView.webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
println("Load Started")
}
override fun onPageFinished(view: WebView, url: String) {
println("Load Finished")
}
}
}
Both solution actually same. So onPageStarted function run when page started to load in the other hang onPageFinished function works when page loaded entirely. You may want to write your as an example loadFinishedRun() function inside onPageFinished funtion.
Better late than never

Categories

Resources