I've made an Android app that authenticates with a server via an Asynctask that does this in background on user button click. While this is happening, the user is shown a loading popup or a spinner. This is all currently working.
I am now trying to create redundancy by setting up another server just in case the 1st one goes down. To accommodate this change on my app, I thought of making 2 asynctasks call one after the other.
However, I am encountering some issues.
As test urls, I have been using 10.255.255.1 (un-routable address) and www.google.com:81 (blocked port, dropped packets).
In case server 1 does not respond or takes a long time (tested using the urls above), I am trying to do a timer on the asynctask for 5-10 seconds which I have tried using
new MyAsyncTask().execute(serverurl1).get(5000, TimeUnit.MILLISECONDS);
It didn't work. Curiously, it waited 5 seconds before showing the spinner wheel and then performed as normal (waiting forever past 5 or even 10 second mark).
I guess this 2nd issue question hinges on the 1st question but how do I make sure the 1st asynctask is done (or has executed and gone over the time limit) before creating the 2nd asynctask to query the server 2? I guess I could use STATUS.running (but only after making sure the 1st asynctask has run its course?
For this one, I have tried shooting out 2 asynctasks like so:
new MyAsyncTask().execute(serverurl1); new MyAsyncTask().execute(serverurl2);
hoping that shooting out 2 asynctasks would get me some sort of response. Even if 1 failed, we'd still get authenticated but alas, it didn't work.
I know some of you might say that by serializing the behavior of asynctask, then it defeats the purpose of it. I use it to show the spinner on screen while the app is checking itself with the server.
Questions:
- if an asynctask is stopped/killed by timer or other things, is onPostExecute still called? I'm wondering if this would be a good place to put the 2nd asynctask if it is ALWAYS called.
My ideal solution would be:
user clicks button
asynctask 1 runs and queries with server 1
if something goes wrong, asynctask 1 is killed after timer runs out
asynctask 2 then runs with query to server 2
if something goes wrong, asynctask 2 is killed after timer runs out
(no process that runs forever and clear error message shown)
OR
user clicks button
asynctask 1 runs and queries with server 1
if something goes wrong, asynctask 1 is killed after timer runs out
user is then informed to retry (internally set a flag to query server 2)
user clicks on button again
asynctask 2 then runs with query to server 2
if something goes wrong, asynctask 2 is killed after timer runs out
(again, no process that runs forever and clear error message shown)
Thanks.
I call the async block using:
private void startTask() throws IOException {
String url = "http://google.com:81";
//String url = "http://10.255.255.1";
String url2 = "someurlthatworks";
// tried this
new MyAsyncTask().execute(url);
new MyAsyncTask().execute(url2);
// and this
try {
new MyAsyncTask().execute(url).get(5000, TimeUnit.MILLISECONDS);
}catch(Exception e){}
}
I saw this on How can I put a timer in an AsyncTask without creating another thread? (edited with my variables):
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
new MyAsyncTask.execute(url);
}
}, 5000);
Would it work for my issue?
Here is my asynctask code block: class MyAsyncTask extends AsyncTask {
@Override
protected void onPreExecute() {
super.onPreExecute();
showDialog(DIALOG_DOWNLOAD_PROGRESS);
}
@Override
protected String doInBackground(String... urls) {
int count;
InputStream input = null;
HttpURLConnection httpconnection = null;
try {
URL url = new URL(urls[0]);
httpconnection = (HttpURLConnection) url.openConnection();
httpconnection.connect();
httpconnection.setConnectTimeout(7000);
httpconnection.setReadTimeout(10000);
// check here if there is connectivity, server is accessible, http code is 200
// return error message if any of the above not found
int lengthOfFile = httpconnection.getContentLength();
input = httpconnection.getInputStream();
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
publishProgress(""+(int)((total*100)/lengthOfFile));
}
String msg = new String(data);
if(msg.contains(someinfo)) {
allow = true;
}
input.close();
} catch (Exception e) {}
return null;
}
protected void onProgressUpdate(String... progress) {
mProgressDialog.setProgress(Integer.parseInt(progress[0]));
}
@Override
protected void onPostExecute(String unused) {
dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
if(allow){
Toast.makeText(getBaseContext(),"Success",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getBaseContext(),"Failed",Toast.LENGTH_SHORT).show();
}
}
}
as I've been told
httpconnection.setConnectTimeout(7000);
httpconnection.setReadTimeout(10000);
should work for my problem but somehow it doesn't and the asynctask just keeps waiting.
Update:
As suggested by Marcin Jędrzejewski that I move connect and read timeouts before connect, I get:
... [socket][1] - [socket][13] here ...
[socket][14:42141] exception
[CDS]close[42141]
close [socket][/0.0.0.0:42141]
[socket][14] connection www.google.com/4.35.153.212:81;LocalPort=59339(7000)
[CDS]connect[www.google.com/4.35.153.212:81] tm:7
[socket][15:59339] exception
[CDS]close[59339]
close [socket][/0.0.0.0:59339]
[socket][15] connection www.google.com/4.35.153.237:81;LocalPort=56148(7000)
[CDS]connect[www.google.com/4.35.153.237:81] tm:7
[socket][16:56148] exception
[CDS]close[56148]
The setconnecttimeout seems to be the timeout each time it attempts a connection but is there any way to set how many times it retries a connection instead of always going 16 tries?