calling AsyncTask in main thread inside a for loop - java

I have someclass which do large network operations and it do take some time to complete,and hence i put it in AsyncTask .I have to do this process 'n' times so in the main thread using a for loop i called this asynctask n times.will it throw any error since there is an interrupt in completing the for loop.?
// inside main thread
for(i=0;i<n;i++)
{
new asynctask().execute(new someclass());
}

Running mutliple AsyncTask is not recommended, but if it is few times, then it will work but all async task will run serially not in parallel. But if you want async tasks to run parallelly then you can call it's executeOnExecutor(..) method where you have to pass THREAD_POOL_EXECUTOR as parameter. You can search on google you can find many links. Here is an example for your help.

don't call AsyncTask n times just put your for loop in onPostExecute() and do any task up to n times
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
} catch (Exception e) {
e.printStackTrace();
}
return resp;
}
#Override
protected void onPostExecute(String result) {
// execution of result of Long time consuming operation
for(i=0;i<n;i++)
{
//do your operation here
}
}
#Override
protected void onPreExecute() {
// Things to be done before execution of long running operation. For
// example showing ProgessDialog
}
#Override
protected void onProgressUpdate(String... text) {
// Things to be done while execution of long running operation is in
// progress. For example updating ProgessDialog
}
}
}

Related

java - make if for async task time limit

here is my piece of code:
Thread one = new Thread() {
public void run() {
try {
new LongOperation(finalJson)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
.get(30000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
};
one.start();
i want to say if AsyncTask past 30000 MILLISECONDS and didn't finish the job return a message, how i can code this? thanks
I would prefer doing it using an AsyncTask.
Copy-pasting from the link:
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.
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 package such as Executor, ThreadPoolExecutor and
FutureTask.
Said this, configuring an AsyncTask is pretty simple, just create a class like the following:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method works on the UI thread.
//this is the first to run before "doInBackground"
mTextView.setText("we start!");
}
#Override
protected String doInBackground(String... params) {
try {
//do whatever your async task needs to do. This method works async
//you can also call an UI callback from here with the publishProgress method. This will call the "onProgressUpdate" method, and it has to respect his type.
publishProgress("we go on!");
} catch (InterruptedException e) {
Thread.interrupted();
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//this method works on the UI thread
//it get the "doInBackground" return value.
mTextView.setText(result);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(String... values) {
//this method works on UI thread, so it can access UI components and ctx
mTextView.setText(values[0]);
}
}
This is a basic example on how to create an AsyncTask, you can use it like this (form activity/fragment):
AsyncTaskExample asyncTask = new AsyncTaskExample();
asyncTask.get(30000, TimeUnit.MILLISECONDS);
This will set a timeout on your async operation. Look here for the exact Exception/return
For any further question, ask freely. Hope this helps
Edit:
I just noticed you have an AsyncTask inside your thread. Since AsyncTask is already async, I would avoid doing this and simply call the AsyncTask with the method I gave you before. In that way the AsyncTask will run up to the given TimeSpan :)
See the code below: It may help you.
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
}
};
timer.start();
And if you have an async task. Then do like below in doInBackground method:
#Override
protected Void doInBackground(Void... voids) {
//simply do your job
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
return message;
}
};
timer.start();
return your_reult;
}

How to execute AsyncTask in endless loop?

I have AsyncTask class with methods like this(class: ApiConnector):
#Override
protected String doInBackground(Void... voids)
{
return getToken(); //<-- do many the most important things and return String
}
and
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
and then in my Activity:
new ApiConnector()
{
#Override
public void onPostExecute(String result)
{
Log.d("here: ", result);
}
}.execute();
It work's fine when I execute this one time, but i have to do this in endless loop to take always fresh token like fresh apples in my market. I tried something like that:
while (true)
{
new ApiConnector()
{
#Override
public void onPostExecute(String result)
{
Log.d("here!", result);
}
}.execute();
Thread.sleep(1000);
}
and many many stupid things, but i can't find working way. All thread bussiness is tricky for me. Give me some kick and I manage this for sure.
You don't want to do this. All AsyncTasks run on one thread. If you infinitely loop inside an AsyncTask, you'll starve all other tasks. If you have each task start a new task, then you'll still risk major starvation issues.
If you want to do this (and I'm not sure you really do, but lets ignore that), the correct way is to use a Thread. A Thread can just have a giant while(true) loop and a sleep statement at the end.
Like hrskrs commented I would prefer using a Handler to execute something repeatedly. The main advantage is that postDelayed makes the run() method execute in the main application thread - so you can access and change UI components.
Here's an example:
public class MyTest implements Runnable {
private final static int INTERVAL = 5000;
private Handler mHandler;
private MyTest() {
mHandler = new Handler();
}
public void start() {
run();
}
public void stop() {
mHandler.removeCallbacks(this);
}
#Override
public void run() {
// put here the logic that you want to be executed
mHandler.postDelayed(this, INTERVAL);
}
}

Wait for multiple AsyncTask to complete

I am parallelizing my operation by splitting it in the exact number of cores available and then, by start the same number of AsyncTask, performing the same operation but on different portions of data.
I am using executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ...) in order to parallelize the execution of them.
I would like to know when every thread finishes its job so that combine all results and perform further operations.
How can I do?
You could also simply decrement a counter in a shared object as part of onPostExecute. As onPostExecute runs on the same thread (the main thread), you won't have to worry about synchronization.
UPDATE 1
The shared object could look something like this:
public class WorkCounter {
private int runningTasks;
private final Context ctx;
public WorkCounter(int numberOfTasks, Context ctx) {
this.runningTasks = numberOfTasks;
this.ctx = ctx;
}
// Only call this in onPostExecute! (or add synchronized to method declaration)
public void taskFinished() {
if (--runningTasks == 0) {
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this.ctx);
mgr.sendBroadcast(new Intent("all_tasks_have_finished"));
}
}
}
UPDATE 2
According to the comments for this answer, OP is looking for a solution in which he can avoid building a new class. This can be done by sharing an AtomicInteger among the spawned AsyncTasks:
// TODO Update type params according to your needs.
public class MyAsyncTask extends AsyncTask<Void,Void,Void> {
// This instance should be created before creating your async tasks.
// Its start count should be equal to the number of async tasks that you will spawn.
// It is important that the same AtomicInteger is supplied to all the spawned async tasks such that they share the same work counter.
private final AtomicInteger workCounter;
public MyAsyncTask(AtomicInteger workCounter) {
this.workCounter = workCounter;
}
// TODO implement doInBackground
#Override
public void onPostExecute(Void result) {
// Job is done, decrement the work counter.
int tasksLeft = this.workCounter.decrementAndGet();
// If the count has reached zero, all async tasks have finished.
if (tasksLeft == 0) {
// Make activity aware by sending a broadcast.
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this.ctx);
mgr.sendBroadcast(new Intent("all_tasks_have_finished"));
}
}
}
You should use a CountDownLatch. Here the documentation with examples:
java.util.concurrent.CountDownLatch
Basically you give a reference of CountDownLatch to your threads, and each of them will decrement it when finished:
countDownLatch.countDown();
The main thread will wait on the termination of all threads using:
countDownLatch.await();
First, add this class to your project
public abstract class MultiTaskHandler {
private int mTasksLeft;
private boolean mIsCanceled = false;
public MultiTaskHandler(int numOfTasks) {
mTasksLeft = numOfTasks;
}
protected abstract void onAllTasksCompleted();
public void taskComplete() {
mTasksLeft--;
if (mTasksLeft==0 && !mIsCanceled) {
onAllTasksCompleted();
}
}
public void reset(int numOfTasks) {
mTasksLeft = numOfTasks;
mIsCanceled=false;
}
public void cancel() {
mIsCanceled = true;
}
}
Then:
int totalNumOfTasks = 2; //change this to the number of tasks that you are running
final MultiTaskHandler multiTaskHandler = new MultiTaskHandler(totalNumOfTasks) {
#Override
protected void onAllTasksCompleted() {
//put the code that runs when all the tasks are complete here
}
};
Then in each task - when completed, add the line: multiTaskHandler.taskComplete();
Example:
(new AsyncTask<Void,Void,Void>() {
#Override
protected Void doInBackground(Void... voids) {
// do something...
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
multiTaskHandler.taskComplete();
}
}).execute();
You can use multiTaskHandler.cancel() if you want to cancel the code that runs when all the tasks have completed. For instance - if you have an error (don't forget to also cancel all the other tasks).
* This solution will not pause the main thread!
Another Option could be to store all your new threads in an Array.
Then you could iterate over the Array and wait with thread[i].join for the thread to finish.
see join()
http://developer.android.com/reference/java/lang/Thread.html#Thread(java.lang.Runnable)
When the Iteration is finished all your threads are done and you can work on
RX Merge operator is your friend.
Get rid of AsyncTark is slower than RX and you cannot handle Errors

Android asynctask for max time

I'm trying to read data from a physical device.
For acquiring data I use an asynctask to avoid UI blocking.
When I click a button, I should do twice these (for min and max values):
wait 5 seconds;
acquire data for 1 second.
So the code is written in the OnClickListener of the button.
For the first task I use this method:
new android.os.CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) { }
public void onFinish() { }
}.start();
For the second I'm using an asynctask and in its doInBackground method I have
while(booleanValueMax || booleanValueMin) {
//code
}
(booleanValueMax and booleanValueMin are volatile boolean). Now I set these two to false using a Timer (outside the asynctask):
Timer min = new Timer();
min.schedule(new TimerTask() {
#Override
public void run() {
booleanValueMin = false;
}
}, 1000);
(same for max)
Now I'd like to use the same asynctask to store max and min values. So I know which data I'm acquiring checking the booleans (in the doInBackground method).
if(booleanValueMax)
//store max
else
//store min
The problem is that these variables are always false. And I don't know why.
Isn't there any other way to accomplish my goal instead of use Timer, CountDownTimer, etc.?I'
Just make two separate asynchtask and call them according to your value i.e.
while(booleanValueMax || booleanValueMin) {
//code
}
You have not shown the code that starts your asynctask, but: all asynctasks share the same thread pool. In the simplest case, it is just one thread. Most likely, your asynctask starts and finishes before any of the variables is set. Asynctasks are intended for long operations that do not need to wait. If you want your code to wait for an event, better use a Thread. (Well, it is possible to post messages/runnables to threads, see Looper and Handler.)
Here's an example:
private void executeBigTask(){
BigTask bigTask = new BigTask();
bigTask.execute();
// Check
Handler handler = new Handler();
handler.postDelayed(new Runnable(){
#Override
public void run() {
if (bigTask.getStatus() == AsyncTask.Status.RUNNING){
bigTask.cancel(true);
}
}
}, 10000);
}
protected class BigTask extends AsyncTask<String, String, Integer> {
#Override
protected Integer doInBackground(String... params) {
/**
LONG TASK
*/
return 0;
}
#Override
protected void onCancelled() {
super.onCancelled();
Toast.makeText(MainActivity.this, getString(R.string.task_too_long), Toast.LENGTH_LONG).show();
}
}

Stop the thread started within a object after the object is no longer in a list?

Say I have a class call MyTask
Every time I new a object for MyTask, it will create a thread
boolean mContinueThread = true;
public MyTask (Activity activity) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (mContinueThread) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
});
thread.start();
return null;
};
}.execute();
}
At first I new myTask1, myTask2, myTask3 then add to the List
List<MyTask> myTasks = new ArrayList<MyTask>;
myTasks.add(myTask1);
myTasks.add(myTask2);
myTasks.add(myTask3);
Now there should be 3 threads run on the background, then I renew the by
myTasks = new ArrayList<MyTask>;
And looks like those threads in myTask1, myTask2, myTask3 are still running, the finalize never get called. I know I can set mContinueThread as true for each MyTask objects before I renew the list, but I would like to know is there any way (callback?) I can know those MyTask objects are not no longer in the list and then set mContinueThread as false?
public MyTask (Activity activity) {
...
#Override
protected void finalize() throws Throwable {
mContinueThread = false;
super.finalize();
}
It seems redundant to have an async task which just starts a Thread.You can achieve the desired outcome, by puting the contance of the thread directly into you AsyncTask$doInBackground()
You can call the call the AsyncTask$cancel(boolean mayInterrupt) method, this will rise an InterruptedException, the only thing left to do, is adding a return statement within the catch:
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// cancel was called
return null;
}
return null;
};
Cancel the task like that:
myTasks.get(i).cancel(true);
Don't forget to pass true or it won't work
you have to have a variable for your AsyncTask first, so that you can call:
myTasks.get(0).getMyAsyncTask().cancel(boolean);
As you can see here, it is not that easy to cancel an AsyncTask. After you call cancel(boolean), it will: (from docs:
invoking this method will cause subsequent call to isCancelled() to
return true. onCancelled(Object) will be invoked after doInBackground
instead of onPostxecute. To ensure that a task is cancelled, you
should always check the return value of isCancelled from
doInBackground.
So, you call cancel(booelan) onto your reference variable of your AsyncTask and in doInBackground, you always check for isCancelled() in order to stop some processes in your doInBackground method.
You should handle your doInBackground method manually in order to stop all the executions there. So if you have while(true){ do_something }, then it should become while(true){ if(!isCancelled()) { do_something } }

Categories