Cancel an ongoing connection when user presses back
I have been searching about this but I did not find my specific question. I understand that AskyncTask
can be canceled using .cancel(true)
but this only happens if I have a loop in which I can check the value isCanceled()
.
But my question here is.. how can I cancel an AsyncTask
(that is stuck in httpclient.execute()
) when the user presses back? If the user navigates away from that Activity and goes to another I dont want to have an uncontrolled number of AsyncTask running because this may lead to memory problems, the user could navigate back and forth and create undetermined number of tasks. That is why I want to close them. Anyone knows a way? I post the code I use to connect:
public class Test extends Activity {
@Override
protected void onStart() {
super.onStart();
new ConnectionTask().execute("https://www.mywebserver.com/webservice.php?param1=test");
}
private class ConnectionTask extends AsyncTask<String, Void, String>{
@Override
protected String doInBackground(String... params) {
try {
开发者_如何学编程 HttpClient httpclient = DefaultHttpClient(params,clientConnectionManager);
HttpPost httpPost = new HttpPost(params[0]);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if(httpEntity != null)
return EntityUtils.toString(httpEntity);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
}
Do you know what I should add in onStop() to cancel the ongoing httpClient.execute() function? Sometimes gets stuck almost forever.
I would really appreciate your help, thank you very much in advance.
UPDATE
If I close the ConnectionManager
I have to do the handshaking for https again, right? Look at this code when I create the httpClient
, I use this for https:
HttpClient httpclient = DefaultHttpClient(params,clientConnectionManager);
Thank you all for your quick responses and the variety of solutions exposed here. I will try to use the timeouts (for not having to wait too much) + the cancel()
function to avoid processing onPostExecute
. I will tell if the results are as expected! Thank you very much you all!
according to HttpClient docs, use HttpUriRequest#abort()
to abort request
1.4. Aborting requests
In some situations HTTP request execution fails to complete within the expected time frame due to high load on the target server or too many concurrent requests issued on the client side. In such cases it may be necessary to terminate the request prematurely and unblock the execution thread blocked in a I/O operation. HTTP requests being executed by HttpClient can be aborted at any stage of execution by invoking HttpUriRequest#abort() method. This method is thread-safe and can be called from any thread. When an HTTP request is aborted its execution thread - even if currently blocked in an I/O operation - is guaranteed to unblock by throwing a InterruptedIOException
There is a cancel()
method in AsyncTask
class. Maintain a member to asynctask and cancel it in onDestroy().
then set the member to null.
Update
Use ClientConnectionManager
to shutdown the connection.
http://developer.android.com/reference/org/apache/http/conn/ClientConnectionManager.html
Update 2
Check this link to set the timeout for your connection.
How to set HttpResponse timeout for Android in Java
In onPause()
or onBackButtonPressed()
, call cancel()
on your task. In doInBackground()
right after
HttpResponse httpResponse = httpClient.execute(httpPost);
Check isCanceled()
and immediatelly return if true.
Of course, you still have a risk of having multiple tasks running, but since this operation is UI driven (that is task started by user interactions) there should be at most couple of them running at the same time, provided that timeout on HttpClient is reasonable.
Update
You can shutdown connection manager as well once you determine that the task needs to be canceled. see docs
That should close sockets and cause immediate return from execute()
. Connection manager is set when you create DefaultHttpClient
.
My understanding is that httpClient.execute()
is blocking, so there is no code running to check the value of isCancelled()
. And you'd prefer not to close the Connection Manager.
This might be a bit hacky, but in lieu of any better solutions, what happens if you call Thread.interrupt()
on the Thread whilst httpClient.execute()
is blocking?
A quick test can verify this, just add private instance variable of type Thread
inside your ConnectionTask
definition, set it to Thread.currentThread()
at the top of doBackground()
, and add a public method that calls .interrupt()
on it.
If you're lucky that will cause httpClient.execute()
to immediately exit, throwing an Exception. You can catch that and do any tidup you need to before the method call ends and the AsyncTask
ends naturally.
You can override
onPause()
method of the activity and write the stop connection code there. If the option is specific to back button then you can override
onBackButtonPressed()
method to stop the execute.
Well there is a quick solution for this problem which I used to solve in my case. It may not be the correct way, as when you press back the app will respond immediately but in background network operation will continue (until timeout if you set) without blocking the application:-
Do all you network operation in a new Service say NSERV. Make the NSERV extend the Thread class and do all you network operation in the run method. For more clarity in your code better make the activity/service starting the NSERV also extend Thread class and start the NSERV from their run method.
Then use static fields or singleton to access the variables in the activity/service from NSERV.
EX:
public class NSERV extends Service implements Runnable{
public int onStartCommand (Intent intent, int flags, int startId)
{
Thread t = new Thread (this, "abc");
t.start();
return super.onStartCommand(intent, flags, startId);
}
public void run()
{
//NETWORK OPERATION...
onDestroy();
}
public void onDestroy()
{
stopSelf();
super.onDestroy();
}
}
精彩评论