To the best of my knowledge, AsyncTaskLoader not only has all the capabilities of AsyncTask but also incorporates best practices such as avoiding duplicate threads and premature death built-in.
Is there any justification for using AsyncTask anymore, or should I always use AsyncTaskLoader blindly? I ask this to determine if there is any exceptional scenario that I should be cautious about.
When you have a background job that need to be done no matter activity is destroyed or not: Service or IntentService of some mechanism of background job.
When you have a background job that need to be done and notify back again to UI: using AsyncTaskLoader.
When you have a background job that need to be done and notify back again to user and continue to run although activity is destroyed: using AsyncTask because AsyncTask continue to run when your activity is paused/destroyed/configuration changed ... In this case, be careful you will have memory leak/activity object is null. You must handle by yourself.
Every situation, there are different ways for handling and avoiding. But keep in mind above flow for easiest solution.
In 2017 when this question was asked, AsyncTask was still not deprecated.
However, It is deprecated in Android 11 as AsyncTask requires a lot of checks to avoid memory leaks.
The commit in the Android ASOP project has the #deprecated notice:
#deprecated Use the standard java.util.concurrent or
Kotlin concurrency utilities instead.
AsyncTaskLoader is only useful to load data in an Activity or Fragment. AsyncTask is more versatile and can do any kind of background operation in any kind of component. There are alternatives like RxJava, HandlerThreads, simple threads, etc. but it's certainly not deprecated.
Related
I am new to android developing. And i have searched for this answer. Here’s what i know:
Both AsyncTask and AsyncTaskLoaders do background processing in Android.
The AsyncTaskLoader framework uses AsyncTask.
In most cases, it’s better to perform background processes with the loader instead of Asynctask.
AsyncTask has limitations such as destroying and recreating an activity during orientation changes and other configuration changes. And you can run out of memory of old AsyncTasks dwell in the system.
You CAN use AsyncTask for short or interruptible tasks, tasks that don't need to report back to UI or user, and low-priority tasks that can be left unfinished. All other tasks need to be handled with the Loader.
My question is, do we only use one or the other in the same project or can we use both to handle different processes? If we can use both, can you give an example? If not, can you elaborate?
I am currently studying about Loaders and about how they could overcome changes such as screen orientation during application lifecycle, and so far, from what I have read, AsyncTaskLoader does the same job as AsyncTask and even better. Therefore, should not AsyncTask be considered obsolete or does it provide the developers with some hidden advantages?
I am currently studying about Loaders and about how they could overcome changes such as screen orientation during application lifecycle
The Architecture Components' support for view-models and LiveData is Google's current direction for addressing the problems that loaders tried to address.
AsyncTaskLoader does the same job as AsyncTask and even better
Note that AsyncTaskLoader uses an AsyncTask.
should not AsyncTask be considered obsolete
Yes, insofar as we have other patterns and libraries to use (e.g., RxJava, LiveData). That being said, AsyncTask, used correctly, is an OK option. The challenge is in using it correctly (e.g., from a retained fragment, with care to avoid interacting with the hosting activity on a background thread).
does it provide the developers with some hidden advantages?
Your argument seems to be "an ocean liner has more features than does a rowboat, so shouldn't we consider rowboats to be obsolete?". Ocean liners have their costs, and ocean liners cannot do everything that a rowboat can (e.g., travel in shallow water, be towed behind a truck).
Loaders were designed — to the extent that they ever had a "design" — to:
load data in the background, typically via an AsyncTask
retain that data across configuration changes
automatically deliver updates when the requested data happens to change
Not everything needs that. For example, the loader pattern targets read operations (where we actually "load" data), but it does not really help with write operations (where we are changing the data). Yet we still want to do write operations asynchronously and find out about the results even if we undergo a configuration change. You can squeeze write operations into loaders, but it is not a natural fit. Using an AsyncTask or something else, instead of a loader, would be more natural.
Think this way,
The AsyncTaskLoader can be used at any place where the AsyncTask is.
The main advantage is the ability to persist between the lifecycles.
If you use an AsyncTask and call a Network Operations to get some data from the Internet and the User rotates the phone, your AsyncTask will have to start the task again to grab the data, and this could be potentially dangerous to your application because you could have a memory leak.
So, in any case, Loaders are an evolution of the AsyncTask, they are basically improved AsyncTasks.
I believe that the AsyncTask is still alive because when you are performing some simple task in the Background Thread you can do this more simply using an AsyncTask with an anonymous inner class, and deliver the results right away to the UI Thread.
I know this is the question which was asked many many times. However there is something I never found an answer for. So hopefully someone can shed me some light.
We all know that AsyncTask and Thread are options for executing background tasks to avoid ANR issue. It is recommended that asynctask should only be used for short-running tasks while thread can be used for long-running tasks. The reasons why asynctask shouldn't be used for long tasks are well-known which is about the possible leak caused by asynctask since it may continue running after an activity's destroyed. That is convincing. However, it also leads to some other questions:
Isn't thread also independent from activity lifecycle? Thus, the risk with asynctask can also be applied to thread. So why thread is suitable for long-running tasks?
Looks like the risk of asynctask is only applicable when using it with activity. If we use it in service (not IntentService since IntentService stops after its work's completed), and as long as we can guarantee to cancel the asyntask when the service's stopped, can we use it for long-running tasks? and doesn't it means it's risk free to use asynctask in services?
I've played with rxjava for a while and really like it. It eliminates the need of worrying about threading (except you have to decide in which thread to subscribe and observe the emitted data). From what I can see, rxjava (in conjunction with some other libs like retrofits) seems to be a perfect replacement of asynctask and thread. I'm wondering if we could completely forget about them or there is any specific case that rxjava can't achieve what asynctask and thread can do that I should be aware of?
Thanks
Since no one's replying. I'm answering my own questions then.
The reason why AsyncTask is recommended for only short tasks (around 5 seconds) is there is no method to cancel a running AsyncTask. There exists a method called AsyncTask.cancel(true) which invokes onCancelled(Result result). However, according to the docs, this method "runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object[]) has finished." (https://developer.android.com/reference/android/os/AsyncTask.html). On the other hand, Thread can be stopped with Thread.interrupt().
There shouldn't be any problem running an AsyncTask within a Service provided that you are aware of the cancellation limitation of AsyncTask and the possibility of memory leak can be created by AsyncTask. Note that, there is obviously no need to use an AsyncTask in an IntentService which is already running in a worker thread.
This is a very experience-based question. I guess there would be no complete answer. What we can do is to understand Rx and being aware of the its limitations to determine where suitable to use it. In my development work, I use RxJava all the time without having any issue. Note that the same memory leaking issue is also applied to RxJava. You can perhaps find one of the specific questions here. There are also a whole bunch of discussions about handling leaking/screen rotation with RxJava that can be easily found by Googling.
AsyncTask and Thread+Handler are not carefully designed and implemented. RxJava, Akka and other frameworks for asynchronous execution seem more carefully developed.
Each technology has its limitations. AsyncTask is for a single parallel task with ability to show progress on UI. However, if activity is regenerated (e.g. because of screen rotating), connection to UI is lost (one possible solution for this problem is at https://github.com/rfqu/AsyncConnector).
Thread+Handler keeps memory for thread stack even when there is no messages to process. This limits the possible number of threads. You can have much more Akka actors or RxJava Subscribers than handler threads, with similar functionality.
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?
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.
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.
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
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.
Since Honeycomb and the v4 Compatibility Library it is possible to use AsyncTaskLoader. From what I understand, the AsyncTaskLoader can survive through config changes like screen flips.
Is it recommended to use AsyncTaskLoader instead of AsyncTask? Does LoaderManager get in the picture too?
But I haven't found any good example(s) about how to correctly use the AsyncTaskLoader. The docs also provide no examples. Can anyone provide some good examples.
You can have a look at the compatibility library's source code to get more info. What a FragmentActivity does is:
keep a list of LoaderManager's
make sure they don't get destroyed when you flip your phone (or another configuration change occurs) by saving instances using onRetainNonConfigurationInstance()
kick the right loader when you call initLoader() in your Activity
You need to use the LoaderManager to interface with the loaders, and provide the needed callbacks to create your loader(s) and populate your views with the data they return.
Generally it should be easier than managing AsyncTask's yourself. However, AsyncTaskLoader is not exactly well documented, so you should study the example in the docs and/or model your code after CursorLoader.
Comparing AsyncTaskLoader vs. AsyncTask, as you may know, when you rotate your device screen, it may destroy and re-create your activity. To make it clear. let's imagine rotating your device while networking transaction is going on:
AsyncTask will be re-executed as a background thread again, and the previous background thread processing will just be redundant and zombie.
AsyncTaskLoader will just be re-used basing on Loader ID that was registered in Loader Manager before, so re-executing network transaction will be avoided.
In summary, AsyncTaskLoader prevents duplication of background threads and eliminates duplication of zombie activities.
AsyncTaskLoader performs the same function as the AsyncTask, but a bit better. It can handle Activity configuration changes more easily, and it behaves within the life cycles of Fragments and Activities. The nice thing is that the AsyncTaskLoader can be used in any situation that the AsyncTask is being used. Anytime data needs to be loaded into memory for the Activity/Fragment to handle, The AsyncTaskLoader can do the job better.
There are a few issues with using AsyncTasks, though:
Configuration changes can mess things up
Pausing an activity doesn’t pause the AsyncTask
A fair amount of boilerplate code (which means more possible errors)
AsyncTaskLoader doc
Some differences other than described in other answers:
When using AsyncTaskLoader over AsyncTask:
AsyncTaskLoader gives us liberty to load old cached data until new data is returned by forceLoad()
We can set delays to AsyncTaskLoader by setUpdateThrottle() which can prevent consecutive updates to client (Activity/Fragment)
AsyncTaskLoader can be shared to multiple fragments if they have common parent activity and if it was started from getActivity().getSupportLoaderManager()
AsyncTaskLoader is destroyed by LoaderManger when its linked activity is no more available. while we need to manually destroy AsyncTasks if its caller activity destroys. This saves our time from writing all the clearing stuff. AsyncTaskLoader plays well with their respective lifecycles.
So, AsyncTaskLoader is way better than AsyncTask.