Make One AsyncTask Wait For Another One To Complete? - android

I have two Asynchronous tasks each one in a separate class, I can call them in the main thread, simply using:
new RetrieveTask().execute();
new RetrieveTaskImageData().execute();
But I want the first one to finish before starting the second.
This is an example of one of them:
class RetrieveTask extends AsyncTask<String, Void,Void> {
private Exception exception;
protected Void doInBackground(String... urls) {
try {
//Code here
} catch (Exception e) {
this.exception = e;
} finally {
}
return null;
}
protected void onPostExecute() {
//
}
}
How can we achieve this?
EDIT
Can we use new RetrieveTask().execute().getStatus()==..Finished ?
Thank you

This will be achieved automatically because unless you call executeOnExecutor, all AsyncTasks run on the same thread, so two of them can not run concurrently.

I'have 4 async tasks in my main thread and have if statement inside 2 of them, if one works, other one stops. I did removecallback and execute just inside tasks for eachother, worked for me. (i am using kotlin but i think same should work with java)

You have to impelement interface on first AsyncTask and onPostExecute it will callback to main thread. you need to call second AsyncTask on that override callback method.

Related

Hold calling thread until multiple asynctask finishes

I have a background thread which calls 3 asynctasks to perform tasks simultaneously. The calling thread acts as a Queue for 3 sets of these tasks.
So basically I need to call 3 asynctasks simultaneously and once they are completed I want to call the next three tasks on the queue and repeat.
However I am having trouble pausing the caller thread until the three asynctask finishes. As a result the next three tasks in the queue start running before the previous three tasks are completed.
So is there anyway to hold the caller thread until the asynctasks are completed. I know that you can user .get() in asynctask but it will not enable the three asynctasks to run simultaneously.
Following code is rather a pseudocode of the idea. Basically, you'll declare an interface which will check for firing next three AsyncTasks. You'll also need to maintain a counter to see if the number of received response from AsyncTask is multiplied by 3. If it is then you can trigger next three AsyncTasks.
public interface OnRunNextThree{
void runNextThreeTasks();
}
public class MainClass extends Activity implements OnRunNextThree {
private int asyncTasksCounter = 0;
public void onCreate() {
//Initiate and run first three of your DownloadFilesTask AsyncTasks
// ...
}
public void runNextThreeTasks() {
if (asyncTasksCounter % 3 == 0) {
// you can execute next three of your DownloadFilesTask AsyncTasks now
// ...
} else {
// Otherwise, since we have got response from one of our previously
// initiated AsyncTasks so let's update the counter value by one.
asyncTasksCounter++;
}
}
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> {
private OnRunNextThree onRunNextThree;
public DownloadFilesTask(OnRunNextThree onRunNextThree) {
this.onRunNextThree = onRunNextThree;
}
protected Void doInBackground(Void... voids) {
// Do whatever you need to do in background
return null;
}
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
//Got the result. Great! Now trigger the interface.
this.onRunNextThree.runNextThreeTasks();
}
}
}
Async tasks are meant to do things asynchronously.... so this can't be done in a straight forward way...
Even if you manage to do this, it basically defeats the whole point of asynchronous operation.
You should look for a Synchronous network operation.
Check out Volley... It is a google library specially made for network operations and it supports Synchronous operations
http://www.truiton.com/2015/02/android-volley-making-synchronous-request/
There are many other libraries available ... Retrofit is one other good library..

Pause and resume AsyncTask Android

My Android app handle the business logic in a thread implemented by using AsyncTask which is now call the BL thread.
BL want to prompt user to enter some personal data (name, password...) by adding a Fragment on the UI thread. At this point I want to stop the BL thread, wait for user to enter their name, password..., press the OK button and then continue the BL thread.
How can I achieve that on Android?
Pausing AsynkTask is not best choice. Still you may find example of pausing AsynkTask in Google sample app DisplayingBitmaps in ImageWorker class.
private class BitmapWorkerTask extends AsynkTask<Void, Void, BitmapDrawable> {
#Override
protected BitmapDrawable doInBackground(Void... params) {
synchronized (mPauseWorkLock) {
while (mPauseWork && !isCancelled()) {
try {
mPauseWorkLock.wait();
} catch (InterruptedException e) {}
}
}
}
...
}
public void setPauseWork(boolean pauseWork) {
synchronized(mPauseWorkLock) {
mPauseWork = pauseWork;
if (!mPauseWork) {
mPauseWorkLock.notifyAll();
}
}
}
AsyncTask is supposed to do a single/one time task.
That is not a good use of AsyncTask. AsyncTasks should do work and be done, not try hanging around.
You will find dirty solutions on the web with Thread.sleep() for example. Those are really bad solutions.
If you need two different process you should create two different tasks
For your issue you can cancel() your background thread or asynsTask, and when needed create a new one with updated parameters maybe
You should not do it all inside one AsyncTask..
When creating the fragment with the OK button define new button listener which create new thread and will do the rest of the work.
You might want to use service or service intent and not AsyncTask for that so you could seperate the task to seprate functions and still maintain the background running.

Stopping and wrapping 2 sub AsyncTask in android

I need to call task() function from doInBackground() of AsyncTask class. The task function contains 2 sub-async task. So the task() return immediately from doInBackground().
Is it possible to stop(or mark this task done) this task from anywhere else?
How to wrap two sub async task in one.
You don't need to call another AsyncTask from within doInBackground. As a matter of fact, once you get to a high enough API, you'll get an exception. You can call another long running method from within AsyncTask without needing to worry about a thread; you're already in a background thread. If you really feed the need, call another service, but there is no reason to do this.
To stop an AsyncTask, just override OnCancelled. Then you can just call:
task.cancel(true).
EDIT:
If you want to wait for another process to finish before you move on, you can wait for that process to finish by setting a global variable in your class or application and then doing a Thread sleep until done. You will not get an ANR because you are already in a background thread and not on the Main UI:
private boolean processIsDone = false.
//then in your method you are calling from AsyncTask:
private void myLongRunningMethod() {
//do your work here....
//at the end set
processIsDone = true;
}
//in your AsyncTask:
protected Void doInBackground(Void... params) {
//do first part of AsyncTask here
myLongRunningMethod();
do {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!processIsDone);
//finish the process here.
return null;
}
I do not understand the question exactly but maybe this can help. Use this class in your Activity like this:
myTask = new BackgroundAsyncTask().execute();
And cancel this way:
myTask.cancel(true);
This is the code of the class:
private class BackgroundAsyncTask extends AsyncTask<Object , Object ,String> {
protected void onPreExecute(){
// Do Before execute the main task
}
protected String doInBackground(Object... param) {
//Execute the main task and return for example and String
return res;
}
protected void onPostExecute(String result) {
// You can use the String returned by the method doInBackground and process it
}
}
Hope it's help
About your first question, you can catch event when your task is cancelled by onCancelled() method. try like this:
private CancelTask extends AsyncTask {
private boolean cancelled = false;
protected void onCancelled() {
cancelled = true;
}
protected Object doInBackground(Object... obj) {
do {
// do something...
}while(!cancelled)
}
}
and call AsyncTask.cancel(true); when you want to stop.
CancelTask task = new CancelTask();
task.execute();
...
task.cancel(true);
And about second question, I want to know how you handle two "Sub-AsyncTask"s.
I will try to find a solution after you update your code.

How to create a while(true) in a AsyncTask whithout blocking the Activity?

I have created an AsyncTask and I have to create an while(true) on my AsyncTask.
How can I execute such an unbounded loop upon handling a button click in my Activity class without blocking?
How others said a infinit loop without a break condition isn't a nice user experience.
First get a instance for your AsyncTask:
PostTask pt = new PostTask(this);
pt.execute();
Try this in your doInBackground():
while(!this.isCancelled()){
// doyourjobhere
}
If the app is getting closed by the user the AsyncTask have to be stopped in your onPause().
#Override
public void onPause(){
pt.cancel(false);
}
TheAsyncTask.cancel(boolean) sets isCancelled() to true, calls the AsyncTask.onCanceled() method instead of onPostExecute() and can be overwritten for your own purpose.
If you don't like this put your task in a Service.
As said by the others, you should put your 'infinite loop' inside the doInBackground() method of AsyncTask.
However, this loop is not so infinite, because it must end when you exist the activity, or the application.
I suggest changing your while (true) { } to while (! mustStop) { } and set the boolean mustStop as an instance variable of your activity. So you'll be able to cleanly stop the process by setting mustStop=true (it would be a good idea to set this in the onPause method).
So this will be :
public class AsyncBigCalculActivity extends Activity {
private boolean mustStop = false;
#Override
public void onPause() {
super.onPause();
mustStop=true; // Stop the infinite loop
}
....
#Override
protected String doInBackground(String... params) {
mustStop=false;
while (!mustStop) {
...
}
}
you can put the loop within the doInBackground() method of the AsyncTask. As a suggestion, you can add the AsyncTask as an inner class within your Activity.That way you can easily access the variables declared in your activity. Although the android documentation suggests to use AsyncTask only for short tasks. Its more advisable to create a runnable object and put your while loop within the run() method and execute it using ExecutorService, which allows you to run asynchronous code in android in a thread-safe manner.
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html
http://developer.android.com/reference/java/util/concurrent/ExecutorService.html

Android AsyncTask - avoid multiple instances running

I have AsyncTask that processes some background HTTP stuff. AsyncTask runs on schedule (Alarms/service) and sometime user executes it manually.
I process records from SQLite and I noticed double-posts on server which tells me that sometime scheduled task runs and at the same time user runs it manually causing same record to be read and processed from DB twice. I remove records after they processed but still get this.
How should I handle it ? Maybe organize some kind of queing?
You can execute your AsyncTask's on an Executor using executeOnExecutor()
To make sure that the threads are running in a serial fashion please use: SERIAL_EXECUTOR.
Misc: How to use an Executor
If several activities are accessing your DB why don't create a sort of gateway database helper and use the synchronized block to ensure only one thread has access to it at an instant
Or, you can try this to see if the Task is currently running or not:
if (katitsAsyncTask.getStatus().equals(AsyncTask.Status.FINISHED))
katitsAsyncTask.execute();
else
// wait until it's done.
Initialize the AsyncTask to null. Only create a new one if it is null. In onPostExecute, set it to null again, at the end. Do the same in onCancelled, in case the user cancels this. Here's some untested code to illustrate the basic idea.
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class FooActivity extends Activity {
private class MyAsyncTask extends AsyncTask<Foo, Foo, Foo> {
#Override
protected void onPostExecute(Foo foo) {
// do stuff
mMyAsyncTask = null;
}
#Override
protected void onCancelled() {
// TODO Auto-generated method stub
mMyAsyncTask = null;
}
#Override
protected Foo doInBackground(Foo... params) {
try {
// dangerous stuff
} catch (Exception e) {
// handle. Now we know we'll hit onPostExecute()
}
return null;
}
}
private MyAsyncTask mMyAsyncTask = null;
#Override
public void onCreate(Bundle bundle) {
Button button = (Button) findViewById(R.id.b2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mMyAsyncTask == null) {
mMyAsyncTask = new MyAsyncTask();
mMyAsyncTask.execute(null);
}
}
});
}
}
I know this was a while ago now, and you have solved your problem. but I just had a similar problem. Reno's suggestion put me on the right track, but for those who have been finding it difficult to fill in the gaps. Here is how I overcame a similar issue to that of katit's.
I wanted a particular AsyncTask to only run if it was not currently running. And as a forward from Reno's suggestion, the AsyncTask interface has been created to handle all the nitty gritty processes in properly dealing with threads for Android. Which means, the Executor is built in. As this blog suggests:
"When execute(Object.. params) is invoked on an AsyncTask the task is executed in a background thread. Depending on the platform AsyncTasks may be executed serially (pre 1.6 and potentially again in 4+), or concurrently (1.6-3.2).
To be sure of running serially or concurrently as you require, from API Level 11 onwards you can use the executeOnExecutor(Executor executor, Object.. params) method instead, and supply an executor. The platform provides two executors for convenience, accessable as AsyncTask.SERIAL_EXECUTOR and AsyncTask.THREAD_POOL_EXECUTOR respectively. "
So with this in mind, you can do thread blocking via the AsyncTask interface, it also implies you can simply use the AsyncTasks.getStatus() to handle thread blocking, as DeeV suggests on this post.
In my code, I managed this by:
Creating a global variable defined as:
private static AsyncTask<String, Integer, String> mTask = null;
And in onCreate, initialising it as an instance of my AsyncTask called CalculateSpecAndDraw:
mTask = new CalculateAndDrawSpec();
Now when ever I wish to call this AsyncTask I surround the execute with the following:
if(mTask.getStatus() == AsyncTask.Status.FINISHED){
// My AsyncTask is done and onPostExecute was called
mTask = new CalculateAndDrawSpec().execute(Integer.toString(progress));
}else if(mTask.getStatus() == AsyncTask.Status.PENDING){
mTask.execute(Integer.toString(progress));
}else{
Toast.makeText(PlaySpecActivity.this, "Please Wait..", 1000).show();
}
This spawns a new thread if it is finished, or if the thread state is PENDING, the thread is defined but has not been started we start it. But otherwise if the thread is running we don't re-run it, we simply inform the user that it is not finished, or perform what ever action we wish. Then if you wanted to schedule the next event rather than just block it from re running, take a look at this documentation on using executors.
How about just wrapping your check-what-to-send and send-it logic in a synchronized method? This approach seems to work for us.
try having some instance boolean value that gets set to "true" on the asynctask's preexecute then "false" on postexecute. Then maybe in doinbackground check if that boolean is true. if so, then call cancel on that particular duplicate task.
You could keep the state of the task in shared preferences. Check the value (Boolean perhaps) before starting the task. Set the state to finished(true?) in onPostExecute and false in onPreExecute or in the constructor

Categories

Resources