Stop AsyncTask which is waiting for a synchronous method - java

I want to stop/cancel the pendning AsyncTasks which is waiting for a synchronous method.
Below is my code:(Its starting all the 21 AsyncTasks. I want to stop in the middle, for example after 10 asynctasks completed. Can any one suggest a way for it?
for(int i=0;i<21;i++){
SafeAsyncTask<String, Void, LinkInfo[]> mGetLinkInfo = new SafeAsyncTask<String,Void,LinkInfo []>() {
protected LinkInfo[] doInBackground(String... v) {
return downloadLinks(v[0]);
}
protected void onPostExecute(LinkInfo[] links) {
}
};
mGetLinkInfo.safeExecute(i);
}
synchronized void downloadLinks(){
//Lengthy process
}

Well, with your code, you'll get 21 different AsyncTask, all playing at the same time in parallel. So your need to "stop after 10 asynctasks completed" does not make sense...
Maybe you'll want to have an unique asynctask, doing 21 differents parts of the job. Between each part, you then may insert a stop condition :
SafeAsyncTask<Void, Void, LinkInfo[]> mGetLinkInfo = new SafeAsyncTask<Void,Void,LinkInfo []>() {
protected LinkInfo[] doInBackground() {
LinkInfo[] infos = new LinkInfo[21]; // Is this what you want ?
for(int i=0;i<21;i++) {
// Do part i/21 of the job
infos[i] = downloadLinks(i);
if (getStopCondition()) break;
}
return infos;
}
};
mGetLinkInfo.safeExecute();

Related

how to call a function every 5 minutes?

I need to call the speak method every 5 minutes, then i want to run in background the async method called callspeak, that calls back the speak method(a public method of a different class). It has to loop every 5 minutes
class callSpeak extends AsyncTask<String, Void, String> {
activityAudio a = new activityAudio();
#Override
protected String doInBackground(String... strings) {
try
{
while (true){
a.speak();
Thread.sleep(300000);
}
}
catch (InterruptedException e)
{e.getMessage();}
return null;
}
}
If you want to run the method only when the app is open, you can simply use TimerTask.
Timer myTimer = new Timer ();
TimerTask myTask = new TimerTask () {
#Override
public void run () {
// your code
callSpeak().execute() // Your method
}
};
myTimer.scheduleAtFixedRate(myTask , 0l, 5 * (60*1000)); // Runs every 5 mins
If you want to run it in background even if app is not running, you can use AlarmManager and repeat the task every 5 mins.
Hope it helps
You can do like this:
Handler mHandler = new Handler();
Runnable mRunnableTask = new Runnable()
{
#Override
public void run() {
doSomething();
// this will repeat this task again at specified time interval
mHandler.postDelayed(this, yourDesiredInterval);
}
};
// Call this to start the task first time
mHandler.postDelayed(mRunnableTask, yourDesiredInterval);
Don't forget to remove the callbacks from handler when you no longer need it.
The latest and the most efficient way to perform this, even if you come out of the activitiy or close the app is to implement the WorkManager from the AndroidX Architecture.
You can find more details here from the official documentation: Schedule tasks with WorkManager

Waiting for other AsyncTasks' finish in AsyncTask before processing onPostExecute

I'm getting info from an URL and sending that info to multiple URLs. I'm running it on a "for" in AsyncTask, and at onPostExecute of first AsyncTask, I change a TextView and telling that "All is done" to user.
But the thing is even the children of AsyncTask is continuing to being executed, parent AsyncTask executes its onPostExecute. So I need to wait for them and I'm stuck about it.
So, I have two AsyncTask classes. That's the class I send to websites:
class SendTo extends AsyncTask <Object,Object,String>{
#Override
protected String doInBackground(Object... strings) {
....
}
protected void onPostExecute(String s) {
super.onPostExecute(s);
//update ui for gathered information
}
}
That's the task which I get from websites:
class GetFrom extends AsyncTask <Object,Object,String>{
#Override
protected String doInBackground(Object... strings) {
....
String param = anotherMagicalFunctionThatGivesParamToSend(strings[1]);
for(i = 1; i < websites.length; i++){
publishProgress(websites[i],param);
}
return "";
}
protected void onProgressUpdate(final Object... values) {
super.onProgressUpdate(values);
new SendTo().executeOnExecutor(THREAD_POOL_EXECUTOR, values[1], values[0]);
}
protected void onPostExecute(String s) {
super.onPostExecute(s);
//finish things
}
}
I would recommend use callback in this case.
Create an interface:
public interface MyCallback {
public void readycallback(int index_thread);
}
First class:
class SendTo extends AsyncTask <Object,Object,String>{
private MyCallback cb;
private int i;
public SendTo(int i, MyCallback cb) {
this.cb = cb;
this.i = i;
}
#Override
protected String doInBackground(Object... strings) {
....
}
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (cb != null)
cb.readycallback(i);
//update ui for gathered information
}
}
Second class:
class GetFrom extends AsyncTask <Object,Object,String>{
private boolean[] array_of_completed_tasks = new boolean[websites.length - 1];
#Override
protected String doInBackground(Object... strings) {
....
String param = anotherMagicalFunctionThatGivesParamToSend(strings[1]);
for(i = 1; i < websites.length; i++){
publishProgress(websites[i],param);
}
while(!checkIfAllThreadAreCompleted()) {
//waiting all threads
//you can wait
try {
Thread.sleep(10L);// ten milliseconds
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return "";
}
protected void onProgressUpdate(final Object... values) {
super.onProgressUpdate(values);
new SendTo(i, new MyCallback() {
#Override
public void readycallback(int index_thread) {
//this is your ready callback
array_of_completed_tasks[index_thread] = true;
}
}).executeOnExecutor(THREAD_POOL_EXECUTOR, values[1], values[0]);
}
}
private boolean checkIfAllThreadAreCompleted() {
boolean ok = true;
for(i = 0; i < array_of_completed_tasks.length; i++){
ok = ok && array_of_completed_tasks[i];
}
return ok;
protected void onPostExecute(String s) {
super.onPostExecute(s);
//finish things
}
}
Or use Threads for much better coding style. But I really think that using AsyncTask is very ugly methods is real projects.
Run following for loop inside postExecute() of asyncTask as it's anyway not useful running thread inside the thread.
Maintain one global variable which will have count of completed asyncTasks and will be incremented by 1 when each asyncTask will completes it's execution. i.e it will come into postExecute.
In Every postExecute check if that count is equal to number of websites. If that number will be equal to number of websites that basically means all of your data is successfully synced else it's still in process.
It's probably not a good idea to have one AsyncTask simply wait for other AsyncTasks to complete. It makes the code more complex and prevents using that thread in the pool while it's waiting.
If you can, it would be simpler that you launch all AsyncTasks in parallel and have them all call the same method in onPostExecute(). That method would then check if all the results of all the AsyncTasks have been posted and show "All is done" in that case.
If you really want to have one AsyncTask wait in doInBackground() for one or more other AsyncTasks to complete (effectively pausing that background thread), you can use standard Java synchronization mechanisms. I recommend using CountDownLatch.
It's worth noting that synchronizing between background tasks is something that can be achieved quite easily with RxJava rather than using AsyncTask which has been designed for simple use cases.
You can pass you TextView in child asyncTask and update its value in onPost method of child asynchTask .

Cancel AsyncTask after some time

This could be a duplicate question but I did not find what I was looking for.
I am calling an AsyncTask in the UI activity new LoadData().execute(); and in doInBackground I call a method which takes time. I want to interrupt this thread if the data is not return after some time.
Below is the code how I tried to do this.
class LoadData extends AsyncTask<String, String, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
startTime = System.currentTimeMillis();
}
protected String doInBackground(String... args)
{
DataCollector dc = new DataCollector();
data = dc.collectData(query);
//Here I check if the time is greater than 30 seconds then cancel
if(((System.currentTimeMillis()-startTime)/1000)>30)
{
cancel(true);
}
return null;
}
}
But this does not stop the task after 30 seconds, in fact it is taking more time.
I have tried get(long timeout, TimeUnit unit); as well but that does not work either.
Can anyone show me how can I do it or how do I use isCancelled() in doInBackground.
Thanks.
You need a thread that cancels your task after a certain amount of time. That Thread could look like this:
public class TaskCanceler implements Runnable{
private AsyncTask task;
public TaskCanceler(AsyncTask task) {
this.task = task;
}
#Override
public void run() {
if (task.getStatus() == AsyncTask.Status.RUNNING )
task.cancel(true);
}
}
And when you call your AsyncTask, you need to run the cancle task after a certain amount of time (=the timeout, in this case 20 sec)
private Handler handler = new Handler();
private TaskCanceler taskCanceler;
...
LoadData task = new LoadData();
taskCanceler = new TaskCanceler(task);
handler.postDelayed(taskCanceler, 20*1000);
task.execute(...)
It's a good idea if you clean this up on cancel or finish with
if(taskCanceler != null && handler != null) {
handler.removeCallbacks(taskCanceler);
}
You can of course wrap this in an custom implementation of AsyncTask. I've used this pattern many times and it works like a charm. One thing to note, in rare cases the handler would not start, I suspect if you create it in the wrong context it will not survive in certain instances, so I forced the handler to be an the UI Thread with handler= new Handler(Looper.getMainLooper());
You have to do the Time check on a different thread.
What you currently do is: executing the dc.collectData(query) (in background) and once it is ready you check if you should cancel. So if the query takes 1 minute, you will do the cancel check after 1 minute, which is already too late.
What you could do is schedule a TimerTask that should run 30 seconds after the LoadData().execute() and if the timer Task is run, you can cancel the AsyncTask (if it is still running)
I would translate this into an async/await problem making all the expensive methods as async methods.
First, Modify DataCollector's collectData(query) to collectDataAsync(query). (If you can't modify DataCollector, there are work arounds to wrap it in a lambda function or something similar).
Second, change doInBackground as an async task, something like this:
protected async Task<String> doInBackgroundAsync(String... args)
{
DataCollector dc = new DataCollector();
int timeout = 1000;
var task = dc.collectDataAsync(query);
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
data = task.Result;
} else {
// timeout logic
}
}
Basically, you have two tasks inside doInBackgroundAsync: collectDataAsync and a delay task.
Your code waits for the faster one. Then you know which one was and you can react accordingly.
If you also need to cancel collectDataAsync task, then you want to used a cancellationToken.
I use this to solve your problem https://stackoverflow.com/a/11191070/3307066.
Note that now doInBackgroundAsync is a async, so it changes a bit the way of using it.
Hope it helps.
Short answer is you CAN'T cancel an AsyncTask once its started. What you can do, is insert a loop inside doInBackGround() which will check for isCancelled() and if it is set to true sometime in the future - return a value from the function (which will in turn call onPostExecute() if you have defined it);
Note that just because you can't stop an AsyncTask doesn't mean that the OS won't cancel it if it's low on memory. You should have this in mind if you are doing essential tasks in the AsyncTask (ones that you want executed 100%). If so, it is better to use a Service - a component that is automatically killed and restarted by the OS as need.
try this :
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
Courtesy and for more details see this answer.

AsyncTasks do not get collected causing other AsyncTasks to not run

My app uses a lot of AsyncTasks. It is a web app after all. And when I keep track of the Debug tab, I notice every AsyncTask says running behind it and after 5 AsyncTasks, I can't start any AsyncTasks. I fixed it by changing the executor to THREAD_POOL_EXECUTOR which allows 15 threads to be pooled. But the AsyncTasks still show as running.
The AsyncTasks all have InputStreams in them and BufferedReaders in them to read the JSON, but I never call the close() method on the Streamers and Readers. Could this be it, or will the AsyncTask be collected after it's finished no matter what?
If that's the deal, then why can't I run more than 5 AsyncTasks in my app?
Seeing as I put a bounty on it, I will explain this more explicitly
The AsyncTasks all go through their methods. All of them are built the same exact way, except with different BasicNameValuePairs. I am 100% sure there is no easy mistake made in the code.
Here is an example of one of the AsyncTasks:
private class RunningEvent extends AsyncTask<Void, Void, Response> {
#Override
protected void onPreExecute() {
if (Constants.isOnline(getApplicationContext())) {
super.onPreExecute();
} else {
Toast.makeText(getApplicationContext(),
"No internet connection", Toast.LENGTH_LONG).show();
return;
}
}
#Override
protected Response doInBackground(Void... empty) {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(URL);
try {
List<NameValuePair> values = new ArrayList<NameValuePair>(5);
values.add(new BasicNameValuePair("tag", "eventRunning"));
values.add(new BasicNameValuePair("userid", String
.valueOf(response.user.userid)));
post.setEntity(new UrlEncodedFormEntity(values));
HttpResponse httpresponse = client.execute(post);
HttpEntity entity = httpresponse.getEntity();
InputStream stream = entity.getContent();
Log.i("MenuActivity",
"Input streamed, parsing Gson for existing events");
Gson gson = new Gson();
Reader reader = new InputStreamReader(stream);
eventresponse = gson.fromJson(reader, Response.class);
return eventresponse;
} catch (Exception e) {
e.printStackTrace();
Log.e("RunningEvent", "Error sending data to Server");
}
return null;
}
#Override
protected void onPostExecute(Response result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.i("MenuActivity", "Binding button");
if (eventresponse != null) {
if (eventresponse.success == 1) {
eventresponse.user = response.user;
bActivity.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Intent i = new Intent("com.xxx.xxx.EVENT");
i.putExtra("response", eventresponse);
running = false;
switcher.cancel(true);
MenuActivity.this.finish();
startActivity(i);
}
});
} else {
bActivity.setText("Nieuw activity");
bActivity.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Intent i = new Intent("com.xxx.xxx.NEWEVENT");
i.putExtra("response", response);
running = false;
switcher.cancel(true);
MenuActivity.this.finish();
startActivity(i);
}
});
}
} else {
Log.i("RunningEvent", "Response is null");
}
}
}
The example above is the sometimes gets runned as the 6th AsyncTask and it will never enter the doInBackground() method. I believe this is the 5 Thread limit of the SERIAL_EXECUTOR. I "fixed" the problem by putting most AsyncTasks in THREAD_POOL_EXECUTOR, but this is just avoiding it.
What could be the reason that these AsyncTasks never stop running and clogging up the Executor?
android.os.AsyncTask come with two built-in executor. if using SERIAL_EXECUTOR, there is no threadpool and all AsyncTask get execute one at a time in serial order. if using THREAD_POOL_EXECUTOR (I suppose this is what you refer in the question), this allows up to maximum 128 AsyncTask get execute in parallel.
The number 5 you refer and see from debugging is the corePoolSize of underlying threadpool (AKA. THREAD_POOL_EXECUTOR), which is different from maximumPoolSize. check out AsyncTask source code and see how threadpool is implemented:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
... ...
/**
* An {#link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
Check out ThreadPoolExecutor API to see what is the default threadpool behavior created by calling this constructor. Generally speaking, corePoolSize is the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set.
Those 5 AsyncTask you see in debug are actually on core threads which are finished and become idle but never terminated, you can alter this behavior by calling ThreadPoolExecutor.allowCoreThreadTimeOut(boolean).
More story on SERIAL_EXECUTOR
I said SERIAL_EXECUTOR does not use threadpool, this is not true. SERIAL_EXECUTOR is indeed delegate the real work to THREAD_POOL_EXECUTOR, but using ArrayDeque to control the submission of next tasks (next task is submitted iff the previous task is finished), check out the source:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
So whatever you use SERIAL_EXECUTOR or THREAD_POOL_EXECUTOR, there are always 5 core threads shown in threadpool even they are finished and become idle. However, number of core thread (configured by corePoolSize) is not the number of threads (configured by maximumPoolSize) currently running in threadpool.

Waiting for an unknown number of asynchronous tasks

I have a queue of tasks, and a thread that peek the queue once in a few seconds and if there is a task it performs it.
I have another code section (in another thread of course), that creates tasks in a loop (I can't know the number of tasks in advance from outside the loop) and insert them to the queue. The tasks contains some 'result' object, and the external thread (which created those tasks) need to wait for all the tasks to finish and finally get the result from each one of them.
The problem is that I can't pass java Semaphore\CountDownLatch etc to the result object since I don't know the number of monitors in advance.
I also can't use an Executor that uses invokeAll or wait for the Future object since the tasks are unsynchrnized (the external thread just pust the task to a queue and another thread will execute the task when he have time for this).
The only solution I've had in mind is to create some 'Inverted Semaphore' class that holds a set of results and a monitors counter. The getResult function will check if the counter == 0 and if the answer is yes will notify some lock object, and the getResult function will wait for this lock:
public class InvertedSemaphore<T> {
Set<T> resultSet;
int usages;
final Object c;
public InvertedSemaphore() {
resultSet = Collections.synchronizedSet(new HashSet<T>());
usages = 0;
c = new Object();
}
public void addResult(T result) {
resultSet.add(result);
}
public void addResults(Set<T> result) {
resultSet.addAll(result);
}
public void acquire() {
usages++;
}
public void release() {
synchronized (c) {
if (--usages == 0) {
c.notify();
}
}
}
public Set<T> getResults() {
synchronized (c) {
try {
while (usages > 0) {
c.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return resultSet;
}
}
Each addTask method will invoke semaphore.acquire, and each of the (unsynchronized) tasks will invoke semaphore.release in the end of the task.
It sounds pretty complicated and I'm pretty sure there is a better solution for this in java concurrent library or something.
Any idea will be appriciated:)
If the tasks don't need to be processed in order, use an ExecutorCompletionService
More generally, it is not necessary to use invokeAll on an ExecutorService in order to get a Future for the result. ExecutorService#submit could be used for this purpose, or optionally, the task being created could implement Future itself, thus allowing the creator of the task to ask for the result at a later point in time.
Some code:
class MyTask {
AtomicReference<?> result = new AtomicReference<?>();
void run() {
//do stuff here
result.set(/* the result of the calculation */);
}
boolean resultReady() {
return result.get()!=null;
}
? get() {
return result.get();
}
}
... elsewhere in code
void createTasks() {
Collection<MyTask> c = new ...;
while(indeterminable condition) {
MyTask task = new MyTask();
c.add(task);
mysteryQueue.add(task);
}
while(haven't received all results) {
MyTask task = c.get(...); //or iterate or whatever
? result = task.get();
if (result!=null) {
//do stuff, probably remove the task from the collection c would be smart
}
}
}
One idea would be to use a separate queue for the results.
So you will have one blocking queue that thread A places tasks for thread B thereby having a producer-consumer approach, and when each task is completed, the result could be placed in the second result queue inverting the consumer-producer roles since now thread A that originally created the tasks will consume the result from the second queue.
You can do the following:
each producer will hold its own queue. The producer will pass a means to report to this queue to the Task itself. When the task finishes running, it will queue its result to this queue. It is beast described by some code:
class Result{}
interface IResultCallback{
void resultReady(Result r); // this is an abstraction of the queue
}
class Producer implements IResultCallback{
// the producer needs to pass itself to the constructor of the task,
// the task will only see its "resultReady" facade and will be able to report to it.
// the producer can aggragte the results at it will and execute its own computation as
// as soon it is ready
Queue<Result> results; // = init queue
#Override
public void resultReady(Result r) {
results.add(r);
if(results.size() == 9){
operate();
}
results.clear();
}
public void operate(){
// bla bla
}
}
public class Task {
IResultCallback callback;
public Task(IResultCallback callback){
this.callback = callback;
}
public void execute(){
// bla bla
Result r = null; // init result;
callback.resultReady(r);
}
}

Categories

Resources