What happens when replacing AsyncTask with new Asynctask - java

Quick Android question... What happens when you create a new AsyncTask that replaces an existing one? For example you have a simple activity:
public class ExampleActivity extends Activity{
private MyTask myTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// first instance
myTask = new MyTask();
myTask.execute();
// immediately replace first instance
// assume the first instance hasn't finished yet
myTask = new MyTask();
myTask.execute();
}
}
What happens to the first instance? does it run to completion? Is it garbage collected?

Both instance will run separately upto task completetion.
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 with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.

The instance won't be garbage collected until it the task finishes. Be aware that this could cause memory leaks.

Suppose that first instance start at 0ms and end at 9 ms, then second instance at 3ms and end up at some other time so if you it will execute your code parallel in stack .

AsyncTasks run serially, meaning they run one after another. When you set myTask to another AsyncTask, that doesn't get rid of the old one you just started, you just lose the reference to it. Now the 2nd AsyncTask is going to run after the first one is finished.

According to the docs:
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.
Hence the two instance will run in separate thread without linking with one another and will run until completion.

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.
https://github.com/vitkhudenko/test_asynctask

AsyncTask run on UI thread and they are executed serially . Yaa, you will be going to get leaks there. Try running Memory analyzer tool here, you will get to know the about the retain heap here.
You can't run execute on single instance of AsyncTask like:
myTask = new MyTask();
myTask.execute();
myTask.execute(); // Illegal
as, stated in the docs
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
ref : http://developer.android.com/reference/android/os/AsyncTask.html
but what you are trying to do is quite legal.

Related

Does starting an AsyncTask inside onResume method does cost more memory?

I use AsyncTask to update list from local database(sqlite) as the following :
#Override
public void onResume() {
super.onResume();
new MyAsynctask().execute();
}
I need a clear explanation what happen every time when new MyAsynctask execute and what happen to the previous MyAsynctask that was created earlier, and if this way cost more memory?
Your new async task does nothing.
AsyncTasks are executed after each other.
Only when your old async task ends the new one will start running.
AsyncTask is just a implementation of thread to manage Background task and UI updation . AsyncTask is designed to be a helper class around Thread and Handler in android .From the documentation .
AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
So for your question each time you call new MyAsynctask().execute(); A new thread will starts . And the older one will run also if not finished .
To cancel previous task you can use a global instance of task and check if status is RUNNING by getStatus()
if(asyncTask!=null && asyncTask.getStatus()== AsyncTask.Status.RUNNING){
asyncTask.cancel(true);
}
In your case you create new task in onResume() so each time your activity resumes new thread will created and this is not memory efficient solution to refresh screen.
For more detail on cancel task read Section Cancelling a task and cancel(boolean).
If you know how to manage it, then it's not a memory leak.
Your AsyncTask will be executed inside the onResume() function, thus it will run when:
Every-time the Activity is (re)created
You come back from another Activity
You change screen orientantion
You come back from another Application started by an Intent
You close and re-open your App
...
You might want to keep a class field for your AsyncTask and instantiate it in onCreate():
private MyAsyncTask asyncTask;
In case the Activtyis not destroyed (points: 1, 2 (maybe), 4(maybe), 5(maybe)), you can easily check the asyncTask status and cancel it if needed.
The problem is that the old AsyncTask might still be running when you start a new one if the Activity was re-created. And since the Activity instance is new, the asyncTask reference will point to a new Object as well: in that case you will have a savage Thread running in the background.
Unless Android's OS kills Activity's owned Thread (not sure about that), you might still get away by knowing and making sure that your AsyncTask will run for a few seconds at most, without performing any blocking IO operation. But this isn't really an engineered solution.
I'd say, the best and more standard-compliant solution is: by keeping the reference to the AsyncTask in your Activity, just call asyncTask.cancel() in your onPause() method. And you'll be sure that the AsyncTask's thread will be canceled before your Activity is either paused or destroyed.
Your code will then look like this:
private MyAsyncTask asyncTask;
protected void onCreate() {
this.asyncTask = new MyAsyncTask();
}
protected void onResume() {
this.asyncTask.execute();
}
protected void onPause() {
this.asyncTask.cancel();
}

Parallel AsyncTask issue (application doesn't hang in any case)

I have two asyncTasks, say A and B. Both are called from different activities. Situations arise when A needs to be called and then my app moves to another activity and B is called. A's duration is greater than B. Now the problem is that when I invoke A and then move to other activity and invoke B, it waits for A to complete and then B is invoked.
Please understand the question and then downvote if you have to. I've searched thoroughly and then finally decided to ask this one.
How do i make these two AsyncTasks independent of each other?
AsyncTasks post HoneyComb execute on a single thread:
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.
To execute them in parallel use:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
task.execute();
By default AsyncTask uses SERIAL_EXECUTOR i.e. if if you starts an AsyncTask it will use sDefaultExecutor see AsyncTask#execute()
#MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
In your case you need to run your thread in parallel thread pool
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params) for parallel execution
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params) for serial execution
task.execute() default/generally used option
runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
Call your another asynctask in this method.

Code in OnCreate isn't being run in order

I am not writing my whole code, I have the following simple structure:
public class CreateEventActivity extends ActionBarActivity{
int x;
void onCreate(){
new AsyncTask1().execute();//here I change the value of x
Log.i("000000",String.valueOf(x));
}
public AsyncTask1 extends AsyncTask<Void, Void ,Void>{
// process include changing the vlaue of x to 4
Log.i("111111",String.valueOf(x));
}
}
in the log: the log with the tag 000000 appears before the log with tag 111111 what's going on?
First I thought the problem was because I am chainging the value of x in onPostExecute so I did so in doInBackground and the problem still the same.
what's going on?
AsyncTask is asynchronous. Quoting the documentation:
This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
The reason that you use an AsyncTask is to do work in a background thread (e.g., download some data), followed by some work on the main application thread (e.g., update the UI based upon that data).
is there anyway to avoid this?
Get rid of the AsyncTask, or learn how to use it properly. Among other things:
Do not modify the same data in multiple threads without appropriate synchronization logic
Do not try to fork a background thread, then block the main application thread (which appears to be what you want), as that eliminates the entire point of the background thread in the first place
If you have work that you want to do when doInBackground() ends, put that work in onPostExecute(), not in statements that follow your execute() or executeOnExecutor() call.
That's the nature of an Async task.
Async Tasks are mostly being used for long running operations; like webcalls, I/O operations and so on as they can take a while.
If you want to have a callback when the AsyncTask finishes you can override the OnPostExecute() method

Two different AsyncTasks not getting started from a foregroundService

I have written a foreground service which in the onCreate method does this:
public void onCreate(){
//........
startForeground(id,notification);
Task1=new Task(this);
task1.execute();
Task2=new Task(this);
Log.d("T2","Created");
task2.execute();
Log.d("T2","Executed");
}
Now what is happening is that above code is causing task1 to execute(which has a while(true) with sleep of 60 sec after each loop), but never lets task2 start its doInBackground().
I am not sure whats wrong.As per the logcat, its clearly showing that the task2.execute() does get invoked.But why is the doInBackground() of second task is not getting started?
I was initially planning to have two foreground services, but after reading a few SO posts, decided to have only one Service in foreground and let it have two different Asynctasks to do some continuous processing in background. Please help me in making this work!
The default executor for AsyncTask, starting from Honeycomb, is AsyncTask.SERIAL_EXECUTOR, which means that only one task is executing at a given time.
If you need parallelism, just use AsyncTask.THREAD_POOL_EXECUTOR, i.e.
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
instead of just
task.execute(params);
See the Order of Execution section in the documentation for AsyncTask.
It`s simply because since from Android 3.0 AsyncTask-s work in a single background thread:
Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
http://developer.android.com/reference/android/os/AsyncTask.html
So Task2 never run because you run it before a completion of Task1.

Creating another AsyncTask inside of doInBackground

I recently looked through SO to find the answer to the same question here, but there was not an answer directed at the question in regards to the risk of doing so. But basically I want to run another AsyncTask inside the doInBackground() method of another AsyncTask. Is this a bad approach and/or does it leave any potential side effects?
I know that running it in the onPostExecute() works and so far from past experiences I have not had any issues due to the fact that onPostExecute() runs back on the main thread which started a AsyncTask to begin with.
From the API docs:
•The task instance must be created on the UI thread.
doInBackground() runs on the background thread. So you cannot create and run another asynctask from doInBackground().
http://developer.android.com/reference/android/os/AsyncTask. Have a look at the topic under threading rules.
When an asynchronous task is executed, the task goes through 4 steps: (Straight from the doc)
1.onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
2.doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
3.onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
4.onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
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 with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.
Also you can consider using an alternative RoboSpice.https://github.com/octo-online/robospice.
Can make multiple spice request. Notitifes on the ui thread when task is complete. Worth having a look at robospice.
AsyncTask(), with the exception of the Honeycomb releases, execute serially. So, no, you cannot execute another AsyncTask() from within doInBackground() -- I guess I should say that I've never tried it, but it's highly unlikely you're going to achieve the desired affect.
I asked about AsyncTask() execution during one of the Google Office Hours. Straight from their mouths when asked, "Why did it change from serial to parallel and back to serial execution?"; "Because it broke a lot of stuff."

Categories