I am trying to implement a TimeOut error handling on a webview. But unfortunately I am doing something wrong, which is causing me huge headaches. Currently I am using a TimerTask. To check the progress of a webpage for 10 seconds. The idea is if the page takes more than 10 seconds to load, the app should display a custom "no I-net" view.
Here is my code so far:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (mNoInternetConnectionView.getVisibility() == View.VISIBLE) {
mNoInternetConnectionView.setVisibility(View.GONE);
}
mTimer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (webView.getProgress() < 100) {
handleInternetProblems();
}
}
});
}
};
mTimer.schedule(timerTask, 10000, 1);
}
#Override
public void onPageFinished(WebView view, String url) {
cancelTimer();
if (!internetError && webView.getVisibility() != View.VISIBLE) {
webView.setVisibility(View.VISIBLE);
}
}
#SuppressWarnings("deprecation")
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return mCheckoutUrlHandler.handleUrl(webView, url);
}
#TargetApi(Build.VERSION_CODES.N)
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return true;
}
#Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
//handle ssl error
}
#Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
handleInternetProblems();
}
});
And here are my handleInternetProblems() and my cancelTimer():
private void handleInternetProblems() {
internetError = true;
webView.setVisibility(View.GONE);
mNoInternetConnectionView.setVisibility(View.VISIBLE);
mKLLoadingAnimation.hide();
cancelTimer();
}
private void cancelTimer() {
if (mTimer != null) {
mTimer.cancel();
mTimer.purge();
mTimer = null;
}
}
The problem is that if I click on an URL on the webview and I try to load another webpage I get mNoInternetConnectionView and I can see that handleInternetProblems() is called multiple times inside TimerTask. What am I doing wrong? How can I prevent this from happening?
Related
my webview app opens a website that i need to login. but if i login and destroy the app, i need to login again. i want to cache login data and no need to login again until i log out. how can i make the webview app like holding caches? if user dont logout, app must to stay logged in. thanks for helping
here is my code:
WebView webid;
String newString;
ImageView loading;
AnimationDrawable animation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webid = (WebView) findViewById(R.id.webid);
loading = (ImageView)findViewById(R.id.loader);
animation = (AnimationDrawable) loading.getDrawable();
WebSettings webSettings = webid.getSettings();
webSettings.setJavaScriptEnabled(true);
webid.loadUrl("https://ios.mavicell.com");
webid.setWebViewClient(new WebViewClient(){
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
loading.setVisibility(View.VISIBLE);
animation.start();
}
#Override
public void onPageCommitVisible(WebView view, String url) {
super.onPageCommitVisible(view,url);
loading.setVisibility(View.INVISIBLE);
animation.stop();
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
loading.setVisibility(View.INVISIBLE);
animation.stop();
}
});
if (savedInstanceState == null) {
Bundle extras = getIntent().getExtras();
if(extras == null) {
newString= null;
} else {
newString= extras.getString("urlayar");
}
} else {
newString= (String) savedInstanceState.getSerializable("urlayar");
}
if (newString != null) {
webid.loadUrl(newString);
webid.getSettings().setJavaScriptEnabled(true);
webid.setWebViewClient(new WebViewClient(){
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
loading.setVisibility(View.VISIBLE);
animation.start();
}
#Override
public void onPageCommitVisible(WebView view, String url) {
super.onPageCommitVisible(view,url);
loading.setVisibility(View.INVISIBLE);
animation.stop();
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
loading.setVisibility(View.INVISIBLE);
animation.stop();
}
});
}
else {
}
// Logging set to help debug issues, remove before releasing your app.
OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE);
// OneSignal Initialization
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.unsubscribeWhenNotificationsAreDisabled(true)
.init();
}
#Override
public boolean onKeyDown(int keyCode, #NonNull KeyEvent event){
if(event.getAction() == KeyEvent.ACTION_DOWN){
if (keyCode == KeyEvent.KEYCODE_BACK) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Mavicell");
builder.setMessage("Çıkmak istediğinize emin misiniz?");
builder.setNegativeButton("Hayır", null);
builder.setPositiveButton("Evet", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
});
builder.show();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
This below line should do your work
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT)
I have problem with web view.
I don't know how to handle loading data( timeout) in web client when I open web success i turn off wifi and continues open web client. it loading forever.(
Here is xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/web_assignment"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<include
android:id="#+id/retry_assignment"
layout="#layout/layout_retry_web"
android:visibility="gone"
/>
<com.lusfold.spinnerloading.SpinnerLoading
android:id="#+id/spinnerLoalding_assignment"
android:layout_width="wrap_content"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:visibility="gone"
/>
<WebView
android:id="#+id/layout_assignment"
android:layout_width="match_parent"
android:layout_height="match_parent"></WebView>
</RelativeLayout>
Code is:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
tokenManager = new TokenManager(getApplicationContext());
token = tokenManager.GetTokenID();
if (networkStateReceiver.isConnected(this))
checkTimeToken(token);
else {
setVisibleLayout();
}
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onStop() {
super.onStop();
}
private void setVisibleLayout() {
webView.setVisibility(View.GONE);
relativeLayout.setVisibility(View.VISIBLE);
spinnerLoading.setVisibility(View.GONE);
btnRetry.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("onclick", "Tap reload");
loadweb();
}
});
}
private void checkTimeToken(final String token) {
//
}
private void loadweb() {
final String strUrl = URL_Utils.Assignments_Load + token;
Log.d("URL_asiagnmentss :", strUrl);
if (networkStateReceiver.isConnectedNetwork(this)) {
webView.loadUrl(strUrl);
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
spinnerLoading.setVisibility(View.VISIBLE);
webView.setVisibility(View.INVISIBLE);
spinnerLoading.setPaintMode(1);
spinnerLoading.setCircleRadius(20);
spinnerLoading.setItemCount(8);
Log.d("onPageStarted", "onPageStarted");
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
spinnerLoading.setVisibility(View.INVISIBLE);
webView.setVisibility(View.VISIBLE);
}
#Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
}
});
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);
webView.setVisibility(View.VISIBLE);
relativeLayout.setVisibility(View.GONE);
} else
setVisibleLayout();
}
Firts of all create one Boolean variable default true which track of whether timeout or not.
After that on your WebViewClient's onPageStarted method you have to put one thread which trigger at your given time.
In the last, onPageFinished set variable false
As shown in the code :-
public class MyWebViewClient extends WebViewClient {
boolean timeout = true;
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Runnable run = new Runnable() {
public void run() {
if(timeout) {
// do what you want
showAlert("Connection Timed out", "Whoops! Something went wrong. Please try again later.");
}
}
};
myHandler.postDelayed(run, 5000);
}
public void onPageFinished(WebView view, String url) {
timeout = false;
}
}
First time webview loads, thread is called after x seconds, When clicking on a url inside the webview why is the thread not fired again. The thread in pageStart is loading only once, but it needs to fire everytime a url is clicked inside webview.
public class MyAppWebViewClient extends WebViewClient {
public MyAppWebViewClient() {
timeout = true;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
showProgressDialog();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(Constants.DELAYMILIS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(timeout) {
// do what you want
systemUtils.dismissProgressDialog(activity.getResources().getString(R.string.app_name),activity.getResources().getString(R.string.chargement_message_dialog));
}
}
}).start();
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
super.shouldOverrideUrlLoading(view, url);
webContainer.loadUrl(url);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(Constants.DELAYMILIS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(timeout) {
// do what you want
systemUtils.dismissProgressDialog(activity.getResources().getString(R.string.app_name),activity.getResources().getString(R.string.chargement_message_dialog));
}
}
}).start();
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
timeout = false;
cancelCurrentLoading();
}
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
Log.e("ERROR_LOADING_CODE: ", description);
timeout = false;
noConnection();
}
}
/*
Mehtod to dismiss loading spinner
*/
public static void cancelCurrentLoading() {
showWebView();
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
/*
Method to show and hide webview
*/
public static void showWebView(){
webContainer.setVisibility(View.VISIBLE);
}
public static void hideWebView(){
webContainer.setVisibility(View.GONE);
}
I'm developing an application in which I'm using webview to load certain websites. I also have customized actionbar on which I have website navigation button. Here is the view how my layout is looking like:
When I load website my all three buttons are visible, but I want them to be visible at that time only when user has clicked on some URL, so user easily understand the purpose of those buttons.
I have added all the functionalities to those button. Here is my code:
website_back = (ImageButton) cView.findViewById(R.id.website_back);
website_forward = (ImageButton) cView.findViewById(R.id.website_forward);
website_refresh = (ImageButton) cView.findViewById(R.id.website_refresh);
if (v.getId() == R.id.website_back) {
webview.goBack();
}
if (v.getId() == R.id.website_forward) {
webview.goForward();
}
if (v.getId() == R.id.website_refresh) {
webview.reload();
}
My WebViewClient:
private class HelloWebViewClient extends WebViewClient {
public void onPageStarted(WebView view, String url, Bitmap favicon) {
progress.setVisibility(View.VISIBLE);
super.onPageStarted(view, url, favicon);
}
public void onPageFinished(WebView view, String url) {
progress.setVisibility(View.GONE);
super.onPageFinished(view, url);
}
public boolean shouldOverrideUrlLoading(WebView view, String url) {
website_back.setImageResource(R.drawable.webview_back);
view.loadUrl(url);
return true;
}
}
How can I only show those buttons when user has clicked on some URL, on the website launched in the webview?
Any kind of help will be appreciated.
You need to attach a WebViewClient to the WebView to listen in on the URLs that are being fetched.
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.equals(mOriginalUrl)){
//initial url load, ignoring.
}
else {
//url was navigated to - do something
}
return super.shouldOverrideUrlLoading(view, url);
}
#Override
public void onPageFinished(WebView view, String url) {
//page has finished loading
}
});
this worked for me. hope it would be useful for you. try this
ExternalSiteActivity.class
public class ExternalSiteActivity extends Activity{
WebView webView;
String productURL;
ProgressBar progressBar;
ImageButton webBackButton;
ImageButton webForwButton;
ImageButton webRefreshButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.external_site_activity);
productURL= (String) getIntent().getStringExtra("productUrl");
System.out.println(productURL+"**********");
progressBar=(ProgressBar)findViewById(R.id.progress);
progressBar.setVisibility(View.INVISIBLE);
webView = (WebView) findViewById(R.id.webview);
webBackButton=(ImageButton)findViewById(R.id.web_back_button);
webForwButton=(ImageButton)findViewById(R.id.web_forw_button);
webRefreshButton=(ImageButton)findViewById(R.id.web_refresh_button);
webView.setWebViewClient(new MyWebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl(productURL);
webBackButton.setOnClickListener( new View.OnClickListener(){
#Override
public void onClick(View v) {
if(webView.canGoBack())
webView.goBack();
}
});
webForwButton.setOnClickListener( new View.OnClickListener(){
#Override
public void onClick(View v) {
if(webView.canGoForward())
webView.goForward();
}
});
webRefreshButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
webView.reload();
}
});
}
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
Log.v("shouldOverrideUrlLoading", "shouldOverrideUrlLoading");
return true;
}
#Override
public void onFormResubmission(WebView view, Message dontResend,
Message resend) {
Log.v("onFormResubmission", "onFormResubmission");
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
if(webView.canGoBack())
{
webBackButton.setEnabled(true);
}
else
{
webBackButton.setEnabled(false);
}
if(webView.canGoForward())
{
webForwButton.setEnabled(true);
}
else
{
webForwButton.setEnabled(false);
}
progressBar.setVisibility(View.VISIBLE);
Log.v("onPageStarted", "onPageStarted");
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
progressBar.setVisibility(View.INVISIBLE);
}
#Override
public void onLoadResource(WebView view, String url) {
Log.v("on load ","load resources----");
}
// To handle "Back" key press event for WebView to go back to previous screen.
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
I'm working with PhoneGap and Android and have my .html and js files on an external server. When I use the following code, the app loads my external .html files and everything works fine:
this.setIntegerProperty("loadUrlTimeoutValue", 60000);
this.loadUrl("http://www.myserver.com");
However, when work via a WebView I can't seem to set the loadURLTimeoutValue for a WebView:
private WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
webView = (WebView) findViewById(R.id.webview);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.loadUrl("http://www.myserver.com");
}
This doesn't work. How can I set the timeout value on the WebView?
This is a workaround to simulate the described behavior. You can use a WebViewClient, and override the onPageStarted method:
public class MyWebViewClient extends WebViewClient {
boolean timeout;
public MyWebViewClient() {
timeout = true;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
new Thread(new Runnable() {
#Override
public void run() {
timeout = true;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(timeout) {
// do what you want
}
}
}).start();
}
#Override
public void onPageFinished(WebView view, String url) {
timeout = false;
}
}
If timeout, you can load, for example, an error page...
To add the WebViewClient to you WebView, just do this:
webView.setWebViewClient(new MyWebViewClient());
I used this to set a time out for my WebView:
public class MyWebViewClient extends WebViewClient {
boolean timeout = true;
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Runnable run = new Runnable() {
public void run() {
if(timeout) {
// do what you want
showAlert("Connection Timed out", "Whoops! Something went wrong. Please try again later.");
}
}
};
Handler myHandler = new Handler(Looper.myLooper());
myHandler.postDelayed(run, 5000);
}
#Override
public void onPageFinished(WebView view, String url) {
timeout = false;
}
}
The correct way to change the default timeout is using tag <preference /> in config.xml file, for example:
<preference name="loglevel" value="DEBUG" />
<preference name="loadUrlTimeoutValue" value="60000" />
<preference name="errorUrl" value="file:///android_asset/www/connection_error.html" />
For more preference options, refer to Android Configuration.
If you extend CordovaWebView, which you should in order to get the phonegap API, you can just use the following:
this.getIntent().putExtra("loadUrlTimeoutValue", 60000);
Internally, CordovaWebView implements a timeout mechanism similar to the ones proposed in the previous post (default timeout = 2000).
Mind that this is not a documented interface, so it might break in the future.
WebView mWebView = findViewById(R.id.web_view);
mWebView.setWebViewClient(new WebViewClient() {
private volatile boolean timeout;
private volatile String timeoutOnPageStartedURL;
private volatile String timeoutCurrentURL;
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
timeout = true;
timeoutOnPageStartedURL = url;
timeoutCurrentURL = view.getUrl();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (timeout) {
view.post(new Runnable() {
#Override
public void run() {
String currentURL = view.getUrl();
if ((timeoutOnPageStartedURL.hashCode() == currentURL.hashCode()) ||
(timeoutCurrentURL.hashCode() == currentURL.hashCode())) {
// do what you want with UI
}
}
});
}
}
}).start();
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
timeout = false;
}
});
The use of Thread class bothers me calling the WebView from the run function will lead to an exception as the WebView is created and used in another thread.
I would perform this with an AsyncTask.
In this example, I use an AsyncTask to load an error file into the WebView if the timeout was reached. If the page loads properly I cancel the AsyncTask.
The onPostExecute runs in the UI thread so there is no thread safety problem to interact with the WebView:
private class CustomWebViewClient extends WebViewClient {
boolean mPageLoaded;
final int mTimeoutLength = 20000;
WebView mView;
TimeoutCheck timeoutCheckTask;
public CustomWebViewClient()
{
super();
mPageLoaded = false;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
mView = view;
timeoutCheckTask = new TimeoutCheck();
timeoutCheckTask.execute(null,null);
}
public void onPageFinished(WebView view, String url) {
mPageLoaded = true;
timeoutCheckTask.cancel(true);
}
private class TimeoutCheck extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
long count = 0;
while (count < mTimeoutLength)
{
try
{
Thread.sleep( 1000 );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
// Escape early if cancel() is called
if (isCancelled()) break;
count += 1000;
}
return null;
}
protected void onPostExecute(Void result) {
if(!mPageLoaded) {
mbLoadedErrFile = true;
//load error file into the webview
mView.loadUrl("file:///android_asset/url_err_timeout.html");
}
}
}