The documentation for AsyncTask's cancel() method states:
Calling this method guarantees that onPostExecute(Object) is never invoked.
The documentation for AsyncTask.Status.FINISHED states:
Indicates that onPostExecute(Result) has finished.
Does this mean that cancelled AsyncTasks have a status of RUNNING? How can I tell a running task from a cancelled task, in that case?
Based on the source code to AsyncTask, when the background work is done, either onCancelled() or onPostExecute() will be called. After that, the status is set to FINISHED. Prior to that, the task is presumably RUNNING.
You can also call isCancelled() to see if the task was cancelled, before it gets to the FINISHED state.
CommonsWare answer is absolutely correct!
Just wanted to add the specific code snippet from AsyncTask to prove his correctness:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
Related
I am dealing with quite a bit of legacy AsyncTask code and have to write some myself too in our codebase. But, the careful reading of the cancel() method from the docs has confused me quite a bit. The docs say:
Attempts to cancel execution of this task. This attempt will fail if
the task has already completed, already been cancelled, or could not
be cancelled for some other reason. If successful, and this task has
not started when cancel is called, this task should never run. If the
task has already started, then the mayInterruptIfRunning parameter
determines whether the thread executing this task should be
interrupted in an attempt to stop the task.
Calling this method will result in onCancelled(Object) being invoked
on the UI thread after doInBackground(Object[]) returns. Calling this
method guarantees that onPostExecute(Object) is never invoked. After
invoking this method, you should check the value returned by
isCancelled() periodically from doInBackground(Object[]) to finish the
task as early as possible.
So, there might be a scenario where the AsyncTask has finished and returned from doInBackground() but before calling onPostExecute(), the task was canceled through cancel() which resulted in a call to onPostExecute() anyway. This might be dangerous if the cancellation was initiated from onPause() of Activity.
Also, this question on SO supports the documented behavior of cancellation: onPostExecute on cancelled AsyncTask
So, should I start checking for if(isCanceled()) at the start of onPostExecute() from now on?
So, should I start checking for if(isCanceled()) at the start of
onPostExecute() from now on?
Definetly not, it is already checked.
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
ref:AsyncTask.java
I am trying to dismiss dialog on onCancelled(Boolean aBoolean) of AsyncTask :
1. It will get called if I call 'myAsyncTask.cancel(true)' if AsyncTask is running.
2. It won't get called if AsyncTask already called onPostExecute().
Do anyone has idea?
Actually, AsyncTask.cancel() doesn’t kill the Thread with no regard for the consequences. All it does is set the AsyncTask to a “cancelled” state. It’s up to the developer of AsyncTask to adhere cancel state.
One of the strategies is to check isCancelled() from time to time and act appropriately. onPostExecute you can also read “cancelled” state and call onCancelled() (or any other function with common logic) manually.
In short, You can't not.
When you called .cancel(true) methods, AsyncTask execute onCancelled instead of onPostExecute.
onPostExecute means Background Tasks is over, back to UI Thread.
I think there is new way.
In onPostExecute, just adding boolean isProcessing = true;
when you don't process onPostExecute, just switch isProcessing's value to false. (I'm not sure about that way)
#Override
protected void onPostExecute(Long result) {
if (isProcessing) {
Log.d(TAG, "onPostExecute - " + result);
}
}
when calling
cancel(true);
on asyncTaskObj bring user to
onCancelled()
method. when and why
onCancelled(Object result)
will be called and what is the use of it?
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(Object), instead of
onPostExecute(Object) will be invoked after doInBackground(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(Object[]), if possible (inside a loop for instance.)
description for cancel() function
description for isCancelled() function
description for onCancelled() function
Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object),
instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns.
it is from Android Developer documentation developer.android.com/reference/android/os/AsyncTask.html
You may check isCancelled() to finish the working of doInbackground if it has loop
protected Object doInBackground(Object... obj) {
while (/* condition */) {
//.......
if (isCancelled()) break;
}
return myReturn;
}
This is from the documentation...
Runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object[]) has finished.
The default implementation simply invokes onCancelled() and ignores the result. If you write your own implementation, do not call super.onCancelled(result).
Obviously, it gives you the chance to react after the operation has finally been cancelled such as changing the state of some UI components or notifying the user. For example, say you are executing a long running operation such as downloading a file, while the file is downloading you display a progress bar, but you also expose a "cancel" button so that the user can cancel the download.
Once cancel is clicked you can stop the progress bar and display a "Cancelling..." text when "onCancelled" is triggered you can hide the "cancel" button, the status text view and the progress bar.
Hi I have a question about Android AsyncTask.
I have a fragment within an Activity.
That fragment calls AsyncTask where it does something heavy and update the UI in the onPostExecute().
My question is this. LEt's say the user opened the Activity.
Now the fragment is attached and AsyncTask's doInBackground() is called.
Then the user suddenly presses back button to close the activity.
Now, what happens to the execution in the AsyncTask thread?
Does thread also die as soon as the activity is closed?
Or do I have manually check in onPostExecute whether this Fragment is still attached by using isAdded() at the beginning of onostExecute()?
Thanks!
EDIT
In my Fragment, I declare AsyncTask() implicitly.. like this
new AsyncTask<String, Void, Boolean>() {
#Override
protected Boolean doInBackground(String... params) {
return processPlays(plays);
}
#Override
protected void onPostExecute(Boolean result) {
if (!isAdded()) return; // IS THIS FINE?
// UPDATE UI
}
}.execute();
Threads run until they either finish or until Android system dumps the memory. Your AsyncTask will keep running, so you need to do the check if you can't outright cancel it. Else you'll get these situations where your app will crash without you even seeing it open.
Likewise, Fragments can be detached and destroyed during the lifecycle of an app. You can never assume that a Fragment or Activity is still active once returned from an AsyncTask's doInBackground()
On that case the AsyncTask thread will keep running until the end, and if unchecked may crash inside onPostExecute(). Most of the times you'll want to cancel the AsyncTask on the onStop(), onFinish() or even onPause() of the Activity (depending on your application).
You can cancel a Task with the cancel(boolean mayInterruptIfRunning) method. From the Android reference:
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(Object), instead
of onPostExecute(Object) will be invoked after
doInBackground(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(Object[]), if possible
(inside a loop for instance.)
I am using an Android AsyncTask in order to download files from a server. when files are downloaded, I am trying to kill the AsyncTask.
protected void onPostExecute(Void result) {
MyTask.cancel(true);
}
But it stills running (I can see it from the Debug window in eclipse).
How to kill the AsyncTask?
When the AsyncTask is finished running, onPostExecute() will be called. The thread will die. The garbage collector will clean it up. You don't have to do anything. What you're doing is redundant.
Other than that, calling "Cancel" sends and interrupt signal to the thread. If your process can be interrupted, it will stop blocking and continue to execute. You then have to call isCancelled() in doInBackground() and return from the method if isCancelled() is true. After which, onCanceled() and onPostExecute() will be called and the thread will die on it's own like normal.
There is some documentation from here about canceling an AsyncTask, which may be relevant:
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(Object), instead of onPostExecute(Object) will be invoked after doInBackground(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(Object[]), if possible (inside a loop for instance.)"