1

I am developing an android application that rely very much on internet, I retrieve data frequently using this RestClient Class, that wrap some detail on using DefaultHttpClient to do network request.

And I always use different thread to do the HTTP request, I create a class like this:

public class AsyncWorker {

    final String SERVER_URL = "http://api.blabla.com";
    RestClient client = new RestClient();

    public void requestHttp(final String url, final ArrayList<NameValuePair> params, final RequestListener listener) {
        new Thread(new Runnable() {

            public void run() {
                try {
                    client.setUrl(url);
                    client.setParams(params);
                    client.Execute(RestClient.RequestMethod.POST);
                    String response = client.getResponse();
                    listener.onComplete(response);
                } catch (Exception ex) {
                    Log.d("LOGIN", ex.getMessage());
                }
            }
        }).start();
    }
    etc...

So whenever I need to do a HTTP request, I only need to create AsyncWorker object, and provide the RequestListener callback interface.

But the problem is, how can I cancel the HTTP Request when the user press the back/cancel button? and in this case the application still is in one activity, for example I create a dialog, and the user do a request from that dialog, and then back button pressed, the dialog dismissed, and I need to cancel the request on that time.

ayublin
  • 1,855
  • 17
  • 25
  • For others who may encounter this problem too, read about http client in detail here http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html – ayublin Aug 11 '11 at 03:29

4 Answers4

3

I had the same issue and was able to find a fix. Here is what I did:

I used CloseableHttpClient along with other related classes, instead of the DefaultHttpClient that by default comes with Android.

These classes are from https://hc.apache.org/downloads.cgi. OR for direcet access: http://apache.mirrors.hoobly.com//httpcomponents/httpclient/binary/httpcomponents-client-4.3.2-bin.tar.gz

With this, calling the abort() method on the Request object will actually halt the connection. However, using this library is not the solution; reason being that Android already has the outdated HTTPCLIENT library inbuilt, and most classes in the library pointed to by the above link would appear to be missing at runtime.

The problem is that both the packages in the above library and the inbuilt org.apache httpclient package have same namespace, and would result in the use of only the inbuilt org.apache classes provided by Android at compilation.

An example of this issue is found here: java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE.

Thanks to the guys who provided http://code.google.com/p/httpclientandroidlib/ as an option (found in the answer section of java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE)

Recommendation: one place to actually cancel an http request could be within OnCancel Listener of a progress dialog, instead of the AyncTask's onCancelled() callback method.

Community
  • 1
  • 1
Jimmy Ilenloa
  • 1,989
  • 21
  • 21
  • 1
    This is weird, for me using the DefaultHttpClient the IOException that should be thrown when a request is aborted was not happening. (I was aborting if(isCancelled()) within my tasks doInBackground()). It does throw if I abort in the progress dialog's onCancel(), but it's not throwing for me in the onCancelled() of the task itself - all very confusing! – Daniel Wilson Dec 12 '14 at 14:49
1

The RestClient object your using doesn't expose any interrupt() method of DefaultHttpClient (which is the backing object doing most of the work). Not a problem - the DefaultHttpClient doesn't seem to have any interrupt or abort functionality to expose in the first place.

So, your left with a blocking operation on client.Execute().

Your half way to having a solution - which is to put the blocking operation into a Thread. Where your falling down is your architecture - your using a Thread/Listener setup which doesn't give you alot of wiggle room.

Try switching your anonymous Thread to an AsyncTask. This won't solve the problem of you're client.Execute() from blocking but will allow you to throw away the listener (replacing it with onProgressUpdate() or onPostExecute()).

What this will do is allow you call task.cancel(), signalling to the Task it is no longer needed. This will allow you to reassign a new AsyncTask, orphaning the cancelled task, the orphaned thread will then finish quickly as its able and die quietly while the rest of your application gets on with what it needs to.

((On an unrelated note, "Execute()" is a method and shouldn't be capitalised))

Graeme
  • 25,714
  • 24
  • 124
  • 186
  • Thanks, it's now solved, I ended up make use of `AsyncTask`'s `cancel()` method, and do the `abort()` method of the `http uri request` inside `onCanceled()`. – ayublin Aug 15 '11 at 06:43
  • Thanks ayublin. With your last comment that finally provided the solution I needed. I was getting a android.os.NetworkOnMainThreadException when I tried calling abort() in response to a cancel button on the ui thread. – AlanKley Jun 21 '13 at 18:51
0

Use the threading primitives. Have a flag running and set it to true initially. Do your REST requests in a while(running) loop.

In your onPause(), set the running flag to false.

curioustechizen
  • 10,572
  • 10
  • 61
  • 110
  • You might also consider putting the code which sets the flag to `false` within a `synchronized` block. – curioustechizen Aug 10 '11 at 08:38
  • okay i will try it, but the case is it's still on one activity, for example I show a dialog, and the user do the request from there, and press back button, the dialog box dismissed, and I need to cancel the request that time, with this case I can't use onPause(), sorry for being unclear before. – ayublin Aug 10 '11 at 08:48
  • Well, `onPause()` was just an example. My point is - whenever you want to cancel the work that a thread is doing, set a "running" flag (which is a member variable of that thread) to `false`. You can extend this idiom to do stuff like pause and resume threads. In your case, when use dismisses the dialog, set the "running" flag to `false`. – curioustechizen Aug 10 '11 at 08:52
  • Oh I got it, let me try it first, and maybe if you have some spare time, some sample code here or an url to it will be appreciated. thanks :D – ayublin Aug 10 '11 at 09:11
  • where should I put the `while(flag)`? I use `while(flag)` to wrap all code inside `run()`, and if the the flag set to true, it will keep the thread running endlessly, and if it set into false, it will not cancel anything, it will still do the process once. – ayublin Aug 10 '11 at 09:34
  • Oops .. I think I misinterpreted your original question. Apologies! You want to cancel an already started HTTP client, which was started as a one-time request. I was under the assumption that you want to stop making new requests. Please ignore my suggestion. – curioustechizen Aug 10 '11 at 10:23
  • oh, it's okay, I myself should be aware of it from the start too. still thanks for your time.. – ayublin Aug 10 '11 at 10:30
0

I suggest you take a look at the ClientConnectionManager interface. This allows you to do stuff like releasing a connection, shutting down a connection etc. You may need to enhance the implementation of RestClient though - since your RestClient does not expose the underlying DefaultHttpClient object (from which you can get to the ClientConnectionManager using the getClientConnectionManager() method).

curioustechizen
  • 10,572
  • 10
  • 61
  • 110
  • Okay thanks, I thought it could be stopped with something to do with the thread, but now I think I have to enhance the RestClient class. thanks. – ayublin Aug 11 '11 at 03:25