3

I'm having this problem:

I have a main Activity that request information for another class, that class gets that information from a web service, so I do that on a AsyncTask class. While the data is being loaded, the main Activity shows a ProgressDialog, I'm handling the back button so when it's pressed I can dismiss the Dialog, but now I want to cancel the AsyncTask. I created a static boolean var that is "true" when the back button is pressed, so from the doInBackground method from the AsyncTask I check if that var is true, if it's true I cancel the AsyncTask:

@Override protected Void doInBackground(Integer... args) {      
  try {
        ....        
      if ( MainActivity.isDialogCancelled ){
        cancel(true);
        }
        ....
  } catch (Exception e) {
      ....
  } 
}

This seems to work fine, but I'm seeing a InterruptedException warning when I cancel the task this way, why is this happening and how I can avoid them? I'm doing something wrong?

These are the warnings:

01-24 18:40:50.582: W/AsyncTask(22877): java.lang.InterruptedException
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1272)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:220)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask.get(FutureTask.java:83)
01-24 18:40:50.582: W/AsyncTask(22877):     at android.os.AsyncTask$3.done(AsyncTask.java:196)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:294)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask.cancel(FutureTask.java:76)
01-24 18:40:50.582: W/AsyncTask(22877):     at android.os.AsyncTask.cancel(AsyncTask.java:325)
01-24 18:40:50.582: W/AsyncTask(22877):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.lang.Thread.run(Thread.java:1019)

Thanks in advance

WarrenFaith
  • 57,492
  • 25
  • 134
  • 150
Spike777
  • 227
  • 5
  • 12
  • catch it. more to that http://stackoverflow.com/questions/1739515/android-asynctask-and-error-handling – Sergey Benner Jan 24 '12 at 22:23
  • you sure you're doing it at the correct place? Have you read this? Cancelling a task- A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.) – Sergey Benner Jan 24 '12 at 22:52
  • Sorry, I didn't put the whole code, but I'm already catching it, but it still shows the warning on the Logcat, I updated the code on the main post showing the try/catch use – Spike777 Jan 24 '12 at 22:53
  • Please don't use the quote style for code or stack traces, use the code button (or 4 spaces at the beginning of the line) instead. Thanks – WarrenFaith Jan 24 '12 at 22:54
  • @Sergey, I read the paragraph you pasted it, it says that I cant cancel a task at any time... can I cancel a task from the method doInBackground of the class itself? – Spike777 Jan 24 '12 at 22:55
  • http://stackoverflow.com/questions/4748964/android-cancel-asynctask-forcefully read this one mate. it has a good sample there. – Sergey Benner Jan 24 '12 at 22:57
  • and here's another one just in case http://stackoverflow.com/questions/2735102/ideal-way-to-cancel-an-executing-asynctask – Sergey Benner Jan 24 '12 at 23:15
  • Thanks for the links Sergey! I already read them, but I think the issue here is that I'm trying to cancel the task from the method doInbackground, I'm doing that because the Dialog is showed from another class outside the AsyncTask, so I can't do AsyncTask.cancel() when Back is pressed, for that reason I check in the method doInBackground for a static var that knows if the user cancelled or no the Dialog. I think that checking only that static var and not cancelling the task will work for what I'm doing. – Spike777 Jan 24 '12 at 23:26
  • Glad to help and glad you've solved it. – Sergey Benner Jan 24 '12 at 23:44

4 Answers4

0

I believe the other answers here are correct but just to try to explain a bit more thoroughly:

It's not good practice to be calling back to a method of your Activity from your AsyncTask in order to check whether you should cancel or not.

The correct way (as per the documentation):

A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)

(bolding mine)

So, you have the right basic idea in your code, but instead of setting something on your Activity, call the cancel() method of the AsyncTask when you want to cancel it. This changes the return value of the isCancelled() method. Then, inside your doInBackground() method you should check the isCancelled() value and choose your behavior based on the result.

And yes, while it's probably not ideal, I have seen functioning code which calls cancel(true); from inside the doInBackground() method.

matt5784
  • 3,065
  • 2
  • 24
  • 42
0

Cancel(false) just sets the cancel flag of asynctask. If you call cancel(true) it sets the cancel flag of asynctask and also interrupts the background thread that asynctask runs on. That is where the interruptedException can come from.

Kurt Van den Branden
  • 11,995
  • 10
  • 76
  • 85
0

Why don't you use asyncTask.cancel(true); from onPause()??

Navin Ilavarasan
  • 1,271
  • 11
  • 15
  • Because sometimes you want to cancel the download or any long lasting task using a cancel button or the Back button of an android device. – Sergey Benner Jan 24 '12 at 22:40
  • Right, this issue is happening when I try to cancel the task when the Back button is pressed – Spike777 Jan 24 '12 at 22:50
0

Like any other Thread, you must wrap it with try/catch and catch InterruptedException.

Moreover, AsyncTask has a function cancel(boolean), use it instead of what you did ,and check if it's canceled using isCacneled()

Rotemmiz
  • 7,933
  • 3
  • 36
  • 36