EDIT:
I am using a ProgressBar for a Webview that works fine. Now I want to refresh my Webview, which also works. When I am trying to combine them, the Spinner doesn't end at all. This is my code:
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
//Toast.makeText(WebcamsScreen.this,"in runnable",Toast.LENGTH_SHORT).show();
doRefreshingStuff(id);
WebcamsScreen.this.mHandler.postDelayed(m_Runnable, 20000);
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//initialitions
doRefreshingStuff(id);
this.mHandler = new Handler();
this.mHandler.postDelayed(m_Runnable,20000);
doRefreshingStuff(id);
}
public void doRefreshingStuff(String id){
setContentView(R.layout.web4);
webView7 = (WebView) findViewById(R.id.web_4_1);
webView7.getSettings().setJavaScriptEnabled(true);
webView7.getSettings().setJavaScriptEnabled(true);
progressBar = ProgressDialog.show(WebcamsScreen.this, "example", "...");
url="my url";
webView7.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url1) {
view.loadUrl(url1);
return true;
}
public void onPageFinished(WebView view, String url1) {
if (progressBar.isShowing()) {
progressBar.dismiss();
}
}
});
webView7.loadUrl(url);
what must I change?
It looks like you are refreshing your WebView every 20 seconds and popping up a new progress dialog when you do. Your code assumes that the old progress dialog has already been dismissed. If it hasn't, then the progress dialog just became orphaned and will remain on display forever. You can probably fix this by inserting this code:
if (progressBar != null && progressBar.isShowing()) {
progressBar.dismiss();
}
just before the line progressBar = ....
But I wouldn't fix your code that way. You are doing a huge amount of work that you don't need to do. (For instance, you don't need to reload the same content view.) Here's my revised version:
private final Runnable m_Runnable = new Runnable() {
public void run() {
doRefreshingStuff(id);
mHandler.postDelayed(m_Runnable, 20000);
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//initialitions
setContentView(R.layout.web4);
webView7 = (WebView) findViewById(R.id.web_4_1);
webView7.getSettings().setJavaScriptEnabled(true);
webView7.getSettings().setJavaScriptEnabled(true);
webView7.setWebViewClient(new WebViewClient() {
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (!mProgressBar.isShowing()) {
mProgressBar.show();
}
}
public void onPageFinished(WebView view, String url1) {
if (mProgressBar.isShowing()) {
mProgressBar.dismiss();
}
}
});
mProgressBar = new ProgressDialog(this);
mProgressBar.setTitle("example");
mProgressBar.setMessage("...");
mHandler = new Handler();
}
protected void onResume() {
super.onResume();
mHandler.post(m_Runnable);
}
protected void onPause() {
super.onPause();
mHandler.removeCallbacks(m_Runnable);
}
public void doRefreshingStuff(String id) {
url="my url";
webView7.loadUrl(url);
}
Note that I moved the starting of the page loading loop to onResume() and kill the looping in onPause(). You may want slightly different logic, but you should definitely stop looping somehow when your activity pauses or finishes.
Related
Need some advice. I want to be able to redirect the user to a specific link in WebView. Example: we go to the first link and if it directs us to "google.com" then we will have to direct the user to "http://test.com". I made an implementation, put a redirect in shouldOverrideUrlLoading, however, after SplashScreen-loading image done its work, a white background appears and that's it. At the same time, if you remove the code for redirection, then after performing its work, the SplashScreen - loading image, the first link opens and the page from the Internet is displayed correctly. How do I redirect to other pages after opening the first one?
public class MainActivity extends AppCompatActivity {
private WebView webView;
private final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webView);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.loadUrl("http://test/start");
new TaskForRedirecting().execute();
}
public class TaskForRedirecting extends AsyncTask<Boolean, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Boolean... booleans) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d(TAG, "Start loading here");
WebViewClient webViewClient = new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains("google.com")) {
view.loadUrl("http://test1.com");
return false;
} else if (url.contains("yahoo.com")) {
view.loadUrl("http://test2.com");
return false;
} else {
}
return true;
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (request.getUrl().toString() == "google.com") {
view.loadUrl("http://test1.com");
view.loadUrl(request.getUrl().toString());
return false;
} else if (request.getUrl().toString() == "yahoo.com") {
view.loadUrl("http://test2.com");
return false;
}
return true;
}
};
webView.setWebViewClient(webViewClient);
Log.d(TAG, "Do in background: APP is Working!!!");
}
});
return false;
}
#Override
protected void onPostExecute(Boolean success) {
success = false;
if (success) {
Toast toast = Toast.makeText(MainActivity.this, "App is under maintenance!", Toast.LENGTH_SHORT);
toast.show();
} else {
Toast toast = Toast.makeText(MainActivity.this, "Let's start to work!", Toast.LENGTH_SHORT);
toast.show();
}
Log.d(TAG, "upload - final! ");
}
}
}
public class SplashScreenActivity extends AppCompatActivity {
long Delay = 6000;
private final String TAG = "SplashScreenActivity";
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_splash_screen);
new SplashScreen().execute();
}
public class SplashScreen extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void...voids) {
Timer RunSplash = new Timer();
TimerTask ShowSplash = new TimerTask() {
#Override
public void run() {
finish();
Intent intent = new Intent(SplashScreenActivity.this, MainActivity.class);
startActivity(intent);
}
};
RunSplash.schedule(ShowSplash, Delay);
Log.d(TAG, "ShowSplash - final! ");
return null;
}
}
}
Your implementation needs to change a bit, we don't need to set the webview client inside an AsyncTask, instead, we can set it directly but it should be set before we call loadurl.
I have removed the asynctask, and set the client in onCreate method before calling loadUrl.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webView);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
WebViewClient webViewClient = new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains("google.com")) {
view.loadUrl("http://test1.com");
return true;
} else if (url.contains("yahoo.com")) {
view.loadUrl("http://test2.com");
return true;
}
return false;
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (request.getUrl().toString() == "google.com") {
view.loadUrl("http://test1.com");
return true;
} else if (request.getUrl().toString() == "yahoo.com") {
view.loadUrl("http://test2.com");
return true;
}
return false;
}
};
webView.setWebViewClient(webViewClient);
webView.loadUrl("http://test/start");
}
UPDATE
Please check out the shouldOverrideUrlLoading Doc, You should return true when you want to cancel the current load, so when you want to load a different URL, then return true else return false to continue the current load. Returning false means the URL which is being loaded to the webview will continue, your custom URL will not be loaded.
Would like to ask if there's a way to kill / move to another activity in Android if the webview is loading for too long, say example 5 seconds.
you can use
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if(isStillLoading())
//move to the next activity
}
},3000);
you have to impliment the method isStillLoading
You can listen the progress of page loading using WebClient -
private boolean loadingFinished;
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
return false;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap facIcon) {
loadingFinished = false;
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
}
#Override
public void onPageFinished(WebView view, String url) {
loadingFinished = true;
}
});
User Handler to check if the webview is loaded or not after 5 seconds -
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// Will get executed after 5 seconds
if(!loadingFinished)
//move to the next activity
}
},5000); //5000 miliseconds.. i.e. 5 seconds
How do you create a ProgressDialog without showing it? When the WebView starts trying to open a page I want a progress dialog to appear if the page hasn't loaded after two seconds (and disappear if it still hasn't loaded after 30 seconds). The following code is failing because ProgressDialog progress = new ProgressDialog(MainActivity.this);, despite what I've seen in various SO answers, throws a NullPointerException error.
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
// ProgressDialog progress = new ProgressDialog(MainActivity.this); // gives NullPointerException
ProgressDialog progress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = (WebView) findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("http://www.google.com");
webView.setWebViewClient(new WebViewClient() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return false;
}
#Override
public void onPageStarted(WebView view, String url, Bitmap facIcon) {
timerBeginDialog(2000, progress);
progress.setCancelable(true);
timerRemoveDialog(30000, progress);
}
#Override
public void onPageFinished(WebView view, String url) {
drawer.closeDrawer(GravityCompat.START);
progress.dismiss();
}
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
view.loadUrl("file:///android_asset/www/error.html");
drawer.openDrawer(GravityCompat.START);
progress.dismiss();
}
});
.
.
}
public void timerBeginDialog(long time, final ProgressDialog pd){
new Handler().postDelayed(new Runnable() {
public void run() {
pd = ProgressDialog.show(MainActivity.this, "", "Loading...", true); // gives error "Cannot assign a value to final variable pd"
}
}, time);
}
public void timerRemoveDialog(long time, final ProgressDialog pd){
new Handler().postDelayed(new Runnable() {
public void run() {
pd.dismiss();
}
}, time);
}
That's because the context has not been created yet when your initializer runs.
Just place the initialization inside onCreate method.
Move
ProgressDialog progress = new ProgressDialog(MainActivity.this);
inside onCreate
You cannot pass a variable by reference on Java, so what you need to do is to define the variable within the class, which you apparantly have done, and its name is progress, but withing the method call you're referring to variable 'pd' which is the one it takes as parameter.
You should instead set the value of 'progress' to the new ProgressDialog like this:
progress = ProgressDialog.show(MainActivity.this, "", "Loading...", true);
and then on other method
progress.dismiss();
I have a webview on my 4.1.2 Android, which I load with
public class FullscreenActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
final WebView wv=(WebView)findViewById(R.id.webView1);
String sHTML="Webviewtest";
for(int i=0;i<500;i++){
sHTML=sHTML+"Line " + i + "<br>";
}
wv.loadData(sHTML, "text/html", null);
wv.setScrollY(1500);
wv.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
wv.setScrollY(500);
Toast.makeText(getApplicationContext(), "Done! " + wv.getScrollY(), Toast.LENGTH_SHORT).show();
}
});
}
}
I like the webview to scroll down to a specific postition, but it stays on the top.
any ideas ?
When setScrollY() with a button it works, but I like to set the position after laoding the HTML. I also tried to do it with a Handler, which I call in onPageFinished. This does not work too.
I created a very simple Android project, where everyone can download and test:
https://drive.google.com/folderview?id=0B7yz_IQ1CMblUU03cGd5cEotTVE&usp=sharing
This time it is not android's fault,it has provided us with another approach.
try:
public void onPageFinished(WebView v, String url) {
v.evaluateJavascript("window.scrollTo(0,"+expectedPos/a.getResources().getDisplayMetrics().density+");", null);
super.onPageFinished(v, url);
}
My Solution. I don't like it, but it works. All this mess because of the android framework, that doesn't work like expected...
I added a AsyncTask:
private class Waitforloaded extends AsyncTask<String, Integer, Long> {
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(Long result) {
}
#Override
protected Long doInBackground(String... params) {
// TODO Auto-generated method stub
boolean bgo=true;
int iTries=0;
while(bgo){
iTries=iTries+1;
if(iTries>20 || wv.getContentHeight()>0){
bgo=false;
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
wv.setScrollY(1500);
return null;
}
}
Then calling it in
wv.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Waitforloaded wfl=new Waitforloaded();
wfl.execute("");
}
WebView.setScrollY works for me only when I give it some delay with a timer after the WebView is loaded:
webView.loadData(sHtmlTemplate, "text/html", "utf-8");
Timer t = new Timer(false);
t.schedule(new TimerTask() {
#Override
public void run() {
MainActivity.mainactivity.runOnUiThread(new Runnable() {
public void run() {
webView.setScrollY(500);
}
});
}
}, 300); // 300 ms delay before scrolling
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");
}
}
}