Do I need to manage the Android asynchronous task lifecycle? - android

Do I need to call cancel on an asyncTask in a fragment onDestroy event in case the asynchronous task hasn't finished yet when the user hits the back button and leaves the activity?
Do I need to also possibly check whether an existing instance of my asyncTask may still be running in case the asyncTask from the previous visit to the fragmentActivity is still running, hasn't finished or hasn't yet been cancelled?

You don't have to, but you should.
The reason is that it keeps running till it finishes, and starting on honeycomb, it even uses only one thread for all asyncTasks.
Anyway, asyncTask should be usually used for short time tasks, something like 1-10 seconds. It's not a rule, but it will help you achieve the reason why there is an asyncTask - to be able to run tasks in the background.
Here are some notes about asyncTask from the API :
"AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. 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."
API of execute():
"Starting HONEYCOMB, tasks are back to being executed on a single
thread to avoid common application errors caused by parallel
execution. If you truly want parallel execution, you can use the
executeOnExecutor(Executor, Params...) version of this method with
THREAD_POOL_EXECUTOR; however, see commentary there for warnings on
its use."
If you wish to use asyncTask as a background task anyway, verify that there is only one single instance of it (and don't forget to cancel it when not needed), or use the next code which Google recommends to avoid:
public static <T> void runAsyncTaskInMultipleThreads(final AsyncTask<T,?,?> asyncTask,final T... params)
{
if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params);
else asyncTask.execute(params);
}

Related

asynctask doInBackgound() not running if there's a asynctask already running

When the user logs in into my app. I am starting an asynctask to maintain the user session. And that async task is running indefinitely till the user logs out. My problem is that when I try to start other asynctasks, their doInBackground() method is never executed.
I read somewhere that if an async task is already running, we cannot start new async task. I can confirm this because when i removed the user session async task, it worked properly. Is there a workaround?
P.S.: I have already used executeOnExecutor() method. but it didn't help.
For potentially long running operations I suggest you to use Service rather than asynctask.
Start the service when the user logs in
Intent i= new Intent(context, YourService.class);
i.putExtra("KEY1", "Value to be used by the service");
context.startService(i);
And stop the service when the user logs out
stopService(new Intent(this,YourService.class));
To get to know more about Service you can refer this
Service : Android developers
Service : Vogella
To know more about asynctask vs service you can refer this
Android: AsyncTask vs Service
When to use a Service or AsyncTask or Handler?
I read somewhere that if an async task is already running, we cannot start new async task.
Yes,That is fact that you can't run more then 5 (five) AsyncTaskat same time below the API 11 but for more yes you can using executeOnExecutor.
AsyncTask uses a thread pool pattern for running the stuff from doInBackground(). The issue is initially (in early Android OS versions) the pool size was just 1, meaning no parallel computations for a bunch of AsyncTasks. But later they fixed that and now the size is 5, so at most 5 AsyncTasks can run simultaneously.
I have figure out Some Threading rules and i found one major rule is below ,
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
What is definition of AsyncTask?
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
How & Where use it?
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. 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 to use it.
Why you can't use multiple AsyncTask at same time ?
There are a few threading rules that must be followed for this class to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Running multiple AsyncTasks at the same time — not possible?
Test sample of parallel excution of AsyncTasks
Try Executor
You should go with Executor that will mange your multiple thread parallel.
Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
...
Sample Example 1
Sample Example 2
Just like a few others here, I object to the premise of the question.
Your core problem is that you are using an AsyncTask to perform a task beyond its scope. Others have noted this too. Those who offer solutions that can mitigate your problem through low-level threads (even java.util.Concurrent is low-level which is why Scala uses Akka actors as an abstraction), Service, etc. are quite clever, but they are treating the symptom rather than curing the disease.
As for what you should be doing, you are not the first to want to maintain a user session in an Android application. This is a solved problem. The common thread (no pun intended) in these solutions is the use of SharedPreferences. Here is a straightforward example of doing this. This Stack Overflow user combines SharedPreferences with OAuth to do something more sophisticated.
It is common in software development to solve problems by preventing them from happening in the first place. I think you can solve the problem of running simultaneous AsyncTasks by not running simultaneous AsyncTasks. User session management is simply not what an AsyncTask is for.
If you are developing for API 11 or higher, you can use AsyncTask.executeOnExecutor() allowing for multiple AsyncTasks to be run at once.
http://developer.android.com/reference/android/os/AsyncTask.html#executeOnExecutor(java.util.concurrent.Executor, Params...)
I'll share with you, what we do on our App.
To keep user Session (We use OAuth with access/refresh tokens), we create a Singleton in our Application extended class. Why we declare this Singleton inside the MainApplication class? (Thats the name of our class), because your Singleton's life will be tided to the Activity that has created it, so if your Application is running on low memory and Garbage Collector collects your paused Activities, it will release your Singleton instance because it's associated to that Activity.
Creating it inside your Application class will let it live inside your RAM as long as the user keeps using your app.
Then, to persists that session cross application uses, we save the credentials inside SharedPreferences encrypting the fields.
yes starting 2 or more asynctasks simultaneously may cause issues on some devices. i had experienced this issue few months back. i could not predict when the 2nd asyncTask would fail to run. The issue was intermittent may caused by usage of memory as i was executing ndk code in asynctask. but i remember well that it depended on memory of device.
Similar question had been asked before. I would post the link for the similar question.
AsyncTask.executeOnExecutor() before API Level 11
Some users suggest go for Service. My advice is don't go for that path yet. Using service is much more complicated. Even you are using service, you still have to deal with threading, as
Note that services, like other application objects, run in the main
thread of their hosting process. This means that, if your service is
going to do any CPU intensive (such as MP3 playback) or blocking (such
as networking) operations, it should spawn its own thread in which to
do that work....
If we can solve a problem in elegant way, don't go for the complicated way.
I would suggest that, try one of the APIs in java.util.concurrent as suggested in below
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. 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.
I can't give you any code example so far, as I do not know how you design your session managing mechanism.
If you think your long running session managing task shouldn't bind to the life cycle of your main application life cycle, then only you might want to consider Service. However, bear in mind that, communication among your main application and Service is much more cumbersome and complicated.
For more details, please refer to http://developer.android.com/guide/components/services.html, under section Should you use a service or a thread?

Multiple async tasks not executing properly

I am trying to start 6 async tasks at a time in onCreate() of the activity. But I noticed following:
a) If I stay on same activity all the async tasks' doInBackground() execute properly.
b) If I switch to some other activity, only 4 or 5 async tasks' doInBackground() executes. Last async task's doInBackground() never executes.
Can someone tell what I might be doing wrong. I am staring different asynctasks in a for loop. If I do this in onStart(), then all the async tasks are executed again if I switch to this activity. Please help.
Here is the sample code:
For(int i=0;i<7;i++){
webServiceTask= WebServiceTask.getInstance();
webServiceTask.execute("");
}
Maybe you should consider some of the following points:
Is the WebServiceTask retrieving any information that is worth persisting (i.e. not very volatile, with a high risk of the user requesting the same data over and over again): in that case you can offload your work to an (Intent)Service and communicate the result back to your app via a ResultReceiver, or a ContentProvider (just to name a few).
AsyncTasks are not guaranteed to run to completion if no Activity or Service is around to keep your app's process alive.
If it is ok that the WebServiceTasks run after eachother, then you can probably also change your code to use only one AsyncTask that sequentially performs those tasks. You can even consider implementing AsyncTask's progress reporting mechanism.
If the operations performed by the AsyncTask(s) have no meaning once the Activity is closed, be sure to .cancel() them in your onStop() or onPause() lifecycle methods.
Keep bullet 3 of Ed Rowland's answer in mind, which I also posted in my earlier comment to your question.
Happy coding!
You need a Service of some kind to keep your process alive after the user switches away. Once your activity loses focus, Android is free to shut down your process altogether. Or your Activity. Either will cause problems, particularly if you are using the context of an Activity that has been shut down.
The Right Thing to Do (tm) is to implement a Service, and pass the operations off to the service for execution.
There are any of a bunch of reasons why only four tasks are running concurrently. Off the top of my head:
HttpConnection pools connections to servers, and throttles the
maximum number of connetions to any given server to some reasonable
value. 4 sounds about right.
your target server is throttling the number of simultaneous connections.
Your thread pool isn't as large as you think it is. Starting an API 16 (I think) the default threadpool size is one thread! (!!) Rationale: apparently Android OS developers got fed up with Android app developers doing threading wrong. Is it possible your tasks are executing serially? That would more or less fit the symptoms you describe.
But that's kind of a separate issue.

Android AsyncTask for long running operations

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.

Starting AsyncTasks from Handlers in Android

How does the handler message queue work? I know for a fact that the message queue is tied to the thread it is initialized in. If i have 2 tasks(each download from the web), and I initiate an async task from the handler,one for each, will the 2 tasks be executed simultaneously?
I just need to understand, how the queue works..
could anyone please help! :)
First of all, AsyncTask can be executed only on the UI thread. So, even if you have two separate handlers (one for each AsyncTask) they should be both associated with the UI thread.
Secondary, several AsyncTask instances may run either simultaneously or one by one. It depends on the API version. It is better to read documentation about this:
public final AsyncTask execute (Params... params)
Executes the task with the specified parameters.
The task returns itself (this) so that the caller can keep a reference
to it.
Note: this function schedules the task on a queue for a single
background thread or pool of threads depending on the platform
version. When first introduced, AsyncTasks were executed serially on a
single background thread. Starting with DONUT, this was changed to a
pool of threads allowing multiple tasks to operate in parallel.
Starting HONEYCOMB, tasks are back to being executed on a single
thread to avoid common application errors caused by parallel
execution. If you truly want parallel execution, you can use the
executeOnExecutor(Executor, Params...) version of this method with
THREAD_POOL_EXECUTOR; however, see commentary there for warnings on
its use.

ASyncTask does not execute when task.execute() is called

I have an Android application which has the main UI thread, and several other worker threads which I have spawned using ASyncTask.
However, there is a scenario that I can produce every time in which I attempt to spawn a new thread with ASyncTask using task.execute(), and it does not call doInBackground(). The thread never seems to start. Then my application seems to spin for a little while, and then begins to hang.
Here are the threads I am using:
And here is the memory usage on the device:
It does not look as though it is failing to spawn due to memory issues.
Is there some other underlying reason that I do not know of? Maximum number of threads? Is there any way for me to find out why it is not executing?
AsyncTask uses a ThreadPoolExecutor used internally with a core pool size of 5 and a LinkedBlockingQueue. In simpler terms: you can have atmost 5 AsyncTasks active at the same time. Additional tasks will be queued till one of the other AsyncTasks does not return from doInBackground().
You may want to review your code to free up some AsyncTasks. If thats not possible, you can try to create a CustomAsyncTask class in your project based on the original AsyncTask code which can be found here. Try setting the CORE_POOL_SIZE variable to a higher value or using a SynchronousQueue.
Did you read the docs?
Note: this function schedules the task on a queue for a single
background thread or pool of threads depending on the platform
version. When first introduced, AsyncTasks were executed serially on a
single background thread. Starting with DONUT, this was changed to a
pool of threads allowing multiple tasks to operate in parallel. After
HONEYCOMB, it is planned to change this back to a single thread to
avoid common application errors caused by parallel execution. If you
truly want parallel execution, you can use the
executeOnExecutor(Executor, Params...) version of this method with
THREAD_POOL_EXECUTOR; however, see commentary there for warnings on
its use.
Source

Categories

Resources