开发者

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();
}
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜