92

Quoting the documentation for AsyncTask found here, it says:

AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask.

Now my question arises: why? The doInBackground() function runs off the UI thread so what harm is there by having a long running operation here?

0xCursor
  • 2,242
  • 4
  • 15
  • 33
user1730789
  • 5,157
  • 8
  • 36
  • 57
  • 2
    The problem I faced while deploying an app(that uses asyncTask) to an actual device was that the long-running `doInBackground` function freezes the screen if a progress bar is not used. – venkatKA Oct 09 '12 at 10:10
  • 2
    Because an AsyncTask is tied to the Activity it is launched in. So if the Activity is killed, your AsyncTask instance can get killed as well. – IgorGanapolsky Feb 07 '14 at 16:44
  • What if I create the AsyncTask within a Service? Wouldn't that solve the problem? – eddy Sep 04 '14 at 12:06
  • 1
    Use IntentService, Perfect solution to run long operation in background. – Keyur Thumar Feb 01 '17 at 03:44

4 Answers4

121

It is a very good question, it takes time as an Android Programmer to fully understand the issue. Indeed AsyncTask have two main issues that are related :

  • They are poorly tied to the activity life cycle
  • They create memory leaks very easily.

Inside the RoboSpice Motivations app (available on Google Play) we answer that question in detail. It will give an in-depth view of AsyncTasks, Loaders, their features and drawbacks and also introduce you to an alternative solution for network requests : RoboSpice. Network requests are a common requirement in Android and are by nature long running operations . Here is an excerpt from the app :

The AsyncTask and Activity life cycle

AsyncTasks don't follow Activity instances' life cycle. If you start an AsyncTask inside an Activity and you rotate the device, the Activity will be destroyed and a new instance will be created. But the AsyncTask will not die. It will go on living until it completes.

And when it completes, the AsyncTask won't update the UI of the new Activity. Indeed it updates the former instance of the activity that is not displayed anymore. This can lead to an Exception of the type java.lang.IllegalArgumentException: View not attached to window manager if you use, for instance, findViewById to retrieve a view inside the Activity.

Memory leak issue

It is very convenient to create AsyncTasks as inner classes of your Activities. As the AsyncTask will need to manipulate the views of the Activity when the task is complete or in progress, using an inner class of the Activity seems convenient : inner classes can access directly any field of the outer class.

Nevertheless, it means the inner class will hold an invisible reference on its outer class instance : the Activity.

On the long run, this produces a memory leak : if the AsyncTask lasts for long, it keeps the activity "alive" whereas Android would like to get rid of it as it can no longer be displayed. The activity can't be garbage collected and that's a central mechanism for Android to preserve resources on the device.


It is really a very very bad idea to use AsyncTasks for long running operations. Nevertheless, they are fine for short living ones such as updating a View after 1 or 2 seconds.

I encourage you to download the RoboSpice Motivations app, it really explains this in-depth and provides samples and demonstrations of the different ways to do some background operations.

cpx
  • 17,009
  • 20
  • 87
  • 142
Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • @Snicolas Hi. I have an app where it scans data from an NFC tag and sends to server. It works fine in good signal areas but where no signal the AsyncTask that makes the webcall keeps running. eg the progress dialog box runs for minutes and then when it does disappear the screen turns black and unresponsive. My AsyncTask is an inner class. I'm writing a Handler to cancel the task after X secs. The app seems to send old data to the server hours after the scan. Could this be due to AsyncTask not finishing and then maybe completing hours after? I would appreciate any insight. thanks – turtleboy Jul 18 '13 at 21:26
  • Trace to see what happens. But yes, that's quite possible ! If you desin well your asynctask, you can cancel it rather properly, that would be a good starting point if you don't want to migrate to RS or a service... – Snicolas Jul 19 '13 at 05:56
  • @Snicolas Thanks for the reply. I made a post on SO yesterday outlining my problem and showing the handler code i've written to try stop the AsyncTask after 8 seconds. Would you mind having a look at, if you get time? Will calling AsyncTask.cancel(true) from a Handler cancel the task properly? I know i should check periodically the value of iscancelled() in my doInBackgroud, but i don't think applies to my circumstances as i'm just making a one line webcall HttpPost and not publishing updates on the UI.Are there alteratives to AsyncTask eg is it possible to make a HttPost from an IntentService – turtleboy Jul 19 '13 at 09:12
  • here's the link http://stackoverflow.com/questions/17725767/cancelling-asynctask-and-its-progressbar-from-a-handler – turtleboy Jul 19 '13 at 09:12
  • You should have a try at RoboSpice (on github). ;) – Snicolas Jul 19 '13 at 09:31
  • @Snicolas mmm i'm not really that keen to bring in libraries to the app, i'd rather use a fix for AsyncTask, IntentService maybe an option or some pure Java threading alternative to Async. I'm not disregarding RoboSpice but i need to sort this in next few days as my company's client is backing out! 10's of thousands of £ :( Am i right in saying there is no way to forcibly cancel an AsyncTask with just Cancel(true)? – turtleboy Jul 19 '13 at 11:11
  • Is it the same even if I start the AsyncTask inside a Service?? I mean, would the long running operation still be a problem? – eddy Sep 04 '14 at 12:03
  • @eddy, you would still have to deal with the service life cycle. Moreover, it would not be easy to setup a callback.. Anyhow, it would be a bit like using a degraded version of RS, and it has much more than this to offer.. – Snicolas Sep 04 '14 at 13:05
  • @Snicolas Not even using a broadcast receiver or LocalBroadcastManager? – eddy Sep 04 '14 at 14:57
  • @Snicolas question, what if we call .cancel(boolean) on the long running async task from onPause() (before orientation happens), will it stop immediately and prevent the leak? question2, if we create a new thread, do we need to keep an eye on it, when activity get's on background / destroyed - do we need to cancel it too; –  Dec 02 '15 at 11:00
  • Cancelling cancel would probably prevent the leak, though cancelling a task highly depends in its state. For instance if the thread is in IO blocking state, there is no way to cancel it before it returns... And more than all, calling cancel means that you loose the data you already acquired + the time you spent to establish the connection... RS provides a better solution. – Snicolas Jan 12 '16 at 21:59
  • So if I'll implement AsyncTask as a normal class(not inner class) and keep my references valid(it possible with listener/observer pattern) then can I use AsyncTask for long running processes? – Vigen Oct 23 '16 at 20:26
38

why ?

Because AsyncTask, by default, uses a thread pool that you did not create. Never tie up resources from a pool that you did not create, as you do not know what that pool's requirements are. And never tie up resources from a pool that you did not create if the documentation for that pool tells you not to, as is the case here.

In particular, starting with Android 3.2, the thread pool used by AsyncTask by default (for apps with android:targetSdkVersion set to 13 or higher) has only one thread in it -- if you tie up this thread indefinitely, none of your other tasks will run.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks for this explanation.. I could not find anything truly faulty about the use of AsyncTasks for long-running operations (although I usually delegate those to Services myself), but your argument on tie-ing up that ThreadPool (for which you can indeed make no assumptions about its size) seems spot-on. As a supplement to Anup's post about using a service: That service should itself also run the task on a background thread, and not block its own main thread. An option could be an IntentService, or, for more complex concurrency requirements, apply your own multithreading strategy. – baske Oct 09 '12 at 11:33
  • Is it the same even if I start the AsyncTask inside a Service?? I mean, would the long running operation still be a problem? – eddy Sep 04 '14 at 12:04
  • 1
    @eddy: Yes, as that does not change the nature of the thread pool. For a `Service`, just use a `Thread` or a `ThreadPoolExecutor`. – CommonsWare Sep 04 '14 at 12:08
  • Thank you @CommonsWare just the last question, does TimerTasks share the same disadvantages of AsyncTasks? or Is it a whole different thing? – eddy Sep 04 '14 at 12:13
  • 1
    @eddy: `TimerTask` is from standard Java, not Android. `TimerTask` has largely been abandoned in favor of `ScheduledExecutorService` (which, despite its name, is as part of standard Java). Neither are tied to Android, and so you still need a service if you expect those things to run in the background. And, you *really* should consider `AlarmManager`, from Android, so you do not need a service hanging around just watching the clock tick. – CommonsWare Sep 04 '14 at 12:17
  • `has only one thread in it -- if you tie up this thread indefinitely, none of your other tasks will run.` Answered my question :) – zgc7009 Jan 13 '15 at 19:17
4

Aysnc task are specialized threads that are still meant to be used with your apps GUI but whilst keeping resource-heavy tasks of the UI thread. So when stuff like updating lists, changing your views etc require you to do some fetch operations or update operations, you should use async tasks so that you can keep these operations off the UI thread but note that these operations are still connected to the UI somehow.

For longer-running tasks, which don't require UI updation, you can use services instead because they can live even without a UI.

So for short tasks, use async tasks because they can get killed by the OS after your spawning activity dies (usually will not die mid-operation but will complete its task). And for long and repetitive tasks, use services instead.

for more info, See threads:

AsyncTask for longer than a few seconds?

and

AsyncTask won't stop even when the activity has destroyed

Community
  • 1
  • 1
Anup Cowkur
  • 20,443
  • 6
  • 51
  • 84
1

The problem with AsyncTask is that if it is defined as non-static inner class of the activity, it will have a reference to activity. In the scenario where activity the container of async task finishes, but the background work in AsyncTask continues, the activity object will not be garbage collected as there is a reference to it, this causes the memory leak.

The solution to fix this is define async task as static inner class of activity and use weak reference to context.

But still, it is a good idea to use it for simple and quick background tasks. To develop app with clean code, it is better to use RxJava to run complex background tasks and updating UI with results from it.

Arnav Rao
  • 6,692
  • 2
  • 34
  • 31