Let's say I've two AsyncTask.
AsyncTask_A and AsyncTask_B.
I want to execute AsyncTask_B only when AsyncTask_A is totally finished.
I know one that I could execute AsyncTask_B in AsyncTask_A's postExecute() method.
But.. is there any better way?
In this instance you should create a class that acts a singleton that will handle queuing of these tasks (i.e. a list of AsyncTasks within it) where it tracks if any are running, and if they are, queues them instead. Then within the postExecute() of these tasks, all should callback to the queue object to notify them that they are completed, and then within this callback it should then run the next AsyncTask.
This will allow you to:
Call AsyncTaskA without always having to run AsyncTaskB (removing the hard dependency)
Add more AsyncTasks down the track because the dependency on managing these tasks is on the queue object instead of within the AsyncTasks
Queue<ASyncTask> q;
AsyncTask_A async_a;
AsyncTask_B async_b;
q.add(async_a);
q.add(async_b);
while(!q.empty)
{
AsyncTask task = q.pop();
task.execute();
while(task.isRunning())
{
Thread.sleep(SOME_MILLISECONDS) // You can use wait and notify here.instead of sleep
}
}
Related
My situation is this:
first I call first AsyncTask which fetched required Items from database. After that, I call another AsyncTask, which fetches these Item images.
I am getting data from AsynTasks by using callback.
Here is the issue - since I am using callback, in my class I have method processFinish which returns AsyncTask data when it finishes its computation. The problem is with two Async tasks which depend on each other. What should I do now?
You can use the get() method of asyncTask that will wait for the output and wont proceed further
also you can use it with a timeout.
ex new BackgroundTask().execute.get();
or
new BackgroundTask.execute.get(long timeout);
You could execute one AsyncTask inside another, but you should do it inside onPostExecute() because this method runs on the UI thread.
#Override
protected void onPostExecute(Void args) {
new AsyncTask2.execute(..); // Start second task once you've got first results
}
And you call your method processFinish(..) only once, after the second AsyncTask is completed.
Anyway, is there a reason why you use two AsyncTasks ? With your explanations we could believe that you might be able to use only one task.
Basically title. I can run them all in a row or all at once. I need the first one to run to load data for the rest.
Any ideas?
Maybes using handler for the first one so that the code runs on a different thread and trigger the rest when that one completes:
Handler firstTask = new Handler(new Runnable() {
Run() {
//do code
//run rest of tasks
}
}
If you want to make sure that the first AsyncTask has finished and returned the required data before the rest are executed, then override the onPostExecute() method of the first AsyncTask and execute the remaining AsyncTasks inside it.
onPostExecute() is a methode called after the AsyncTask is finished, you can check for the correctness of the received data inside it before executing the other AsyncTasks also inside it.
Your AsyncTasks will be run in the order in which they are submitted and not concurrently, unless you explicitly use the ExecuteOnExecutor method. You can pass data between them accordingly.
Just to be clear, you don't have to do anything at all to make sure that the first task completes before the second (and so on) are run. Each will complete before the next is started, in submission order.
Let's say I have TasksManager which has static List tasks (not sure list is good solution) and there are static methods addTaskToList(MyTask task){tasks.add(task);},
removeTaskFromList(MyTask task){tasks.remove(task);}
Each task in doInBackground() calls first method, and in onPostExecute() there is second method call with "this".
MyTask has String field "method".
I want to cancel tasks of this list where task.getMethod().contains("url")..
not sure this code is good enough for stable working.. looks like onCancelled() of task not always called, multitreading can be dangerous for such methods I think.
for (MyTask task : tasks) {
if (task.getMethod().contains("url")) {
task.cancel(true);
break;
}
}
Is it normal practice to store tasks in this way or you can suggest me more elegant?
Cancelling an AsyncTask isn't always an immediate/obvious thing. If you are using cancel, you also need to make sure doInBackground is aware of isCancelled and you have to stop what you were doing yourself (see the docs for isCancelled).
I wouldn't recommended storing a list of AsyncTask objects and iterating them for doing sequential background work anyway. That sounds like it might get very messy very quickly. Each AsyncTask creates a new Thread, and that doesn't sound like what you want. Rather, you may just want one background thread you can do stuff on?
For one background thread you can use a HandlerThread and your own Looper, as follows:
HandlerThread backThread = new HandlerThread("BackLooper", Thread.NORM_PRIORITY);
backThread.start();
Looper backLooper = backThread.getLooper();
private synchronized void runOnBackThread(Runnable r) {
new Handler(backLooper).post(r);
}
Then each item you want to run in sequence you can post on the back thread by submitting a Runnable. And, you can also use the other Handler post variants too, postDelayed, postAt, and so on.
And, depending on what you're doing you may find IntentService very helpful. IntentService is provided specifically for a "work queue" type pattern. It has one background thread, does whatever you tell it to do ONE AT A TIME when you invoke it, and goes away on its own when it's not needed.
Lastly, if you're looking for a really nice general "task" type library for Android check out Square's Tape. That's not directly related to your question, but I find Tape super handy for more robust "queue it up" task type situations.
Why can an AsyncTask perform only one job? For example,
task = new SubAsyncTask(...); // assume the parameter is correct.
task.execute(...) //
task.execute(...)// calling once again, it throws exeception.
But a Handler can continously perform more than one task:
hd = new Handler(...); // assume the parameter is correct
hd.sendMessage(...); //
hd.sendMessage(...);// no exeception is thrown.
Is an AasyncTask object for a one-time job only? If I don't want to create multiple object for similar task, should I choose Handler?
Handler and AsyncTasks are way to implement multithreading with UI/Event Thread.
Handler allows to add messages to the thread which creates it and It also enables you to schedule some runnable to execute at some time in future.
Async task enables you to implement MultiThreading without get Hands dirty into threads. Async Task provides some methods which need to be defined to get your code works. in onPreExecute you can define code, which need to be executed before background processing starts. doInBackground have code which needs to be executed in background, in doInBackground we can send results to multiple times to event thread by publishProgress() method, to notify background processing has been completed we can return results simply. onProgressUpdate() method receives progress updates from doInBackground method, which is published via publishProgress method, and this method can use this progress update to update event thread, onPostExecute() method handles results returned by doInBackground method.
So, you dont need to call execute method on AsyncTask multiple TImes, instead you can invoke publishProgress.
Because that is how the class was designed. The idea is: do something with UI (show progress dialog, etc.), do work on background thread and return results, update UI. The Handler is fundamentally different: it lets you post messages, but it does not create a background thread for you. If you don't like how AsyncTask works, build something similar by using threads/executors and handlers.
I've got AsyncTask in my Activity, when user clicks button, I start an AsyncTask:
#Override
public void onClick(View view) {
switch(view.getId()){
case R.id.btnLogin:
if(task==null){
task=new LoginTask(this);
task.execute();
}
break;
}
}
But if user clicks button after task is completed, I want it to be executed one more time. What should I do accomplish this? Should I create new task every time user clicks button? Is it OK to create new instance if task is already running?
Also, task is static inner class, in order to handle screen rotation.
Declare task as a class variable.And in the postExecute of AsynchTask make it null.Probably you are done
You can execute your AsyncTask's on an Executor using executeOnExecutor()
Now the pool of threads by default run in parallel :
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 erors
To make sure that the threads are running in a serial fashion please use: SERIAL_EXECUTOR.
Misc: :How to use an Executor
If you want it to run only if previous instances have already finished, then you can use AsyncTask.getStatus(), to only start a new task if the status is AsyncTask.Status.FINISHED.
Don't run it at the same time. Make a queue of the Asynctasks and run one after the other.