How to cancel an asyncTask and executing it multiple times? - android

I'm doing an app which use the new Google Maps V2, when the Map Camera moves, I need to reload the points to the new camera position, I do it with a asynctask.
The problem is when I move the camera position multiple times, app loads the points multiples times. So, I cancel the async task when the camera is moved and I don't load new point until the task is cancelled. I have an empty while loop to do it, Is there a better solution to do it?
// LOAD NEW POIS ASYNC
private void updatePoisInMap( ){
....
if (refresh_pois_async != null) {
refresh_pois_async.cancel(true);
while (!refresh_pois_async.isCancelled()) {
}
}
refresh_pois_async = new RefreshPoisAsync( ).execute( lowerLeftCorner, topRightCorner);
}

Actually, I don't think your while loop will work, or at least not as you would expect it to. The AsyncTask.isCancelled() method is normally used inside the doInBackground() method, to support early cancellation. You have several options to do what you want:
override the onCancelled() method of your AsyncTask. This is guaranteed to be called on the main thread when your doInBackground() is finished and you called cancel() on your task beforehand. In your onCancelled() you can then start a new AsyncTask. Use the isCancelled() in your Task's doInBackground() for early exit, as described above.
don't cancel the current task, but let it run. In the meantime the user may move the map multiple times. As long as a task is still running, just set a flag that it should be rerun. At task completion (override onPostExecute() in your AsyncTask) check the flag and start over if it was set.
combine the above to find the right balance between responsiveness (start loading the right POIs quick enough) and over-processing (don't start every time, but wait for the user to stop scrolling).

Related

Working in the DoInBackground or in the PostExecute of an Asynctask

I'm working in an Android application that is using Microsoft Azure Face Api to get some information from an image. After analizing all the people in the image I get the results in the postExecute() call correctly, but now I need to do some changes if I detect an specific person (all the work is different if this specific person is detected).
I correctly detect this person but I want to know if I can do my work in the DoInBackground() so that I don't need to wait for the result (because if I detected this person I need to send a socket message and the result is not valid).
I actually receive a full list of people in the onResult, then I look through all this list to find the specific person and send the socket message. I want to know if I can send this message as soon as I detect this person in the DoInBackground() and cancel the rest of the execution.
Considering the official documentation :
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.
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.
A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(java.lang.Object), instead of onPostExecute(java.lang.Object) will be invoked after doInBackground(java.lang.Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(java.lang.Object[]), if possible (inside a loop for instance.)
So if you want to stop the task you can do something like:
class myAsyncTaskClass(val pictures:List<Pictures>, Void, Boolean){
fun doInBackground(var args){
// Check all your pictures, if you find the right face stop your task
if (specificPersonIsDectected){
cancel()
return specificPersonIsDectected
}
}
fun onCancelled(var specificPersonIsDectected){
//Notify you found the specific person
}
}
I encourage you to read the official documentation to understand how you should work with AsyncTask
You need use break like this
if (isCancelled()) break;
inside doInBackground method

android async task usage in depending sequence of tasks

My App contains a function that takes time to load ( parsing files).
THe function is called at multiple user case, i.e. from multiple user triggered condition.
Besides, it is called when onCreate is called.
In simple word, the flow is:
User click/OnCreate trigger
Function to parse file
Post to windows
Other postprocessing
I hope the user can click cancel to stop parsing files.
I tried to use asynctask. I know I can put the function to onPostExecute.
But I assume onPostExecute is just for dismiss progress dialog. Or I have to move a lot of codes ( for different cases) to it. Not a good idea.
I do not suppose user to do anything during parsing files.
So, what is the best way to do so? Despite I know it is not good, I think i have to occupy the UI thread.
In simple word, I want to wait for "parsing files", but i do not want to occupy the UI thread, so user can click cancel.
update:
I tried. however, there is a problem:
I use asynctask. I called:
mTask = new YourAsyncTask().execute();
YourAsyncTask.get(); // this force to wait for YourAsyncTask to return.
DoSomethingBaseOnAsyncTaskResult();
YourAsyncTask.get() hold the UI thread. So, there is not loading dialog, and user cannot click cancel from the dialog. It seems I have to move every line after
mTask = new YourAsyncTask().execute();
to
OnPostExecute()
which i did not prefer to do so because DoSomethingBaseOnAsyncTaskResult() can be very different based on the return result. or else, it becomes do everything in YourAsyncTask()
AsyncTasks should ideally be used for short operations (a few seconds at the most.)
When an asynchronous task is executed, the task goes through 4 steps:
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.
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.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.
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.
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.
CODING
To start an Async task
mTask = new YourAsyncTask().execute();
and to cancel that task
mTask.cancel(true);
More detail is available here
In order to use the AsyncTask API, one has to follow the steps described below:
Create a class which extends AsyncTask.
Fill in the generic types available as generics in the class for:
the task execution array parameters
progress array parameters
result array parameters
Implement the method doInBackground(Parameters... parameters). This
method must execute the job which is supposed to be quite demanding.
Optionally, one can implement methods for:
cancelling the task - onCancelled(...)
executing tasks before the demanding task - onPreExecute(...)
reporting progress - onProgressUpdate(...)
executing activities after the demanding task is finished
-onPostExecute(...).

Android Splash screen with data load and delay

I got an activity which should do 2 different things in parallel act as SplashScreen Activity:
wait for 1.5 seconds to display app splash screen
copy some files from assets to device storage in background
Activity implement initial delay (task1) by a handler and file copy (task2) by AsyncTask
Problem: delay of this activity should be such that which both task complete and then start next activity.
I should note that these two task are running in parallel in background and time of copying files may differ each time (some times longer than 1.5seconds, some times shorter).
In other word starting next activity must be synchronized by finishing of both background tasks.
So, How this can be implemented?
I think the easiest thing to do is in the beginning of your async task, get the current time. When you're done with the work, get the current time again. If this is less than 1.5 secs, then do a Thread.Sleep() for the difference.
Start the next activity in the postExecute(). Something like this:
private class DoStuffAsync extends AsyncTask<Void, Integer, Long> {
protected Long doInBackground() {
long start = new Date().getTime();
// copy assents
long end = new Date().getTime();
if ( end-start < 1500 )
Thread.sleep( 1500-(end-start));
return totalSize;
}
protected void onPostExecute(Long result) {
startActivity( new Intent(Activity.this, NewActivity.class));
}
}
Updated: Fixed math problems.
Your design is solid. The detail that you're after to sync the handler and AsyncTask chimes from the realization that both will be executed from the UI thread and therefore you don't need to worry about any concurrency issues. The easiest way then to check whether your new Activity should be started, would be to create two boolean flags. One for the 1.5s timer and the other for the file copy task. Then when either process finished, it checks whether the other flag is set to complete, and if it is, a new Activity will be launched, otherwise the completed task will set it's completed flag to true and when the remaining task completes it will launch the Activity.

I am unsure how to use Async task for a lazy load?

For the down voters,it would be better if you could provide a working solution,not every question need to have a code attached with it,if one is not clear with the concepts how can u expect him to provide you with the code he played with??
This is basically a conceptual question,i tried reading docs but still i couldn't get a better understanding of the topic. i am not sure how i should use async task....
i have used the async task before for displaying an image from internet,
but i am still confused how it works.I know 3 of its functions that are used commonly.
i.e
1.onPreExecute ()
2.doinBackground()
3.onPostExecute()
now i am confused that if i have to populate a list how should it be done??
I know The populating part should be done in the doinbackground(),but after that should i return the result (from the background),after the whole list has been populated, to
onPostExecute() and expect that the list will be loaded on the listview asynchronously
or should i return the result in parts(say a new item has been added to the list,send it to the onpostexecute immediately without waiting for the whole list to be generated, to be displayed and repeat the iteration ) to the onpostExecute()??and manage the lazy load ourselves by doing so?
well.. why don't you see this below android API information..
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
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.
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.
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.
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.
onPreExecute() method is used when starting asynktask function.. typically in this method, someone use progress dialog..
and doInBackground() methos is used when progress dialog is running. in this method you can implement your job(function) that you want. I think this part is the most important point among methods of this asynktask class
and onPostExecute() method is typically used when finished background job.. in order to deliver some kind of data or result.. to View

Finishing an AsyncTask when requested

I am creating a game where the user interacts with the GUI while the computer finds solutions to the puzzle in a background task. The user can choose to end the game any time, at which point I want to stop my background task and retrieve the solutions it found.
This is all working fine except that I can't force the background task to end when the user chooses?!? When the user selects "Done" I have the following:
computerSolutionTask.cancel(true);
// ...disable some GUI buttons etc...
while (computerSolutionTask.getStatus() != AsyncTask.Status.FINISHED){
// ...do nothing...
}
txt_computer.setText(computerSolutionTask.get());
And in my AsyncTask class I am checking "isCancelled()" regularly but it just seems to hang in the while loop I included above.
I feel that I may be going about this whole thing a little incorrectly because I don't really want to cancel the background task I just want it to finish wherever it's up to and return what it has.
This thread appears to be asking the same question I am but has no solution...I'm drawing blanks with all my research thus far and any help would be much appreciated.
A running AsyncTask that is cancelled will never reach onPostExecute and so it will never 'finish'. You don't need to wait for it anyway, if your particular logic requires it use regular synchronization methods.
You need to put the condition inside the doInBackground() method to check whether the AsyncTask is cancelled or in running state.
protected Object doInBackground(Object... x)
{
while (/* condition */)
{
// work...
if (isCancelled()) break;
} return null; }

Categories

Resources