Android AsyncTask blocks back key dispatch Event - android

The Problem is:
My Activity starts an AsyncTask in onStart().
In the doInBackground Method I make a short webrequest, and depending on your network connetion, this may take a little, so I want this task cancelable...
BUT..
After hours of searching, testing and debugging I noticed now, when the user presses the back button during the doInBackground Method, the Keyevent ist always dispatched AFTER my doInBackground method is finished.
So I dont have to wonder why the asynctask never is cancelled when the users presses the backbutton,
the AsyncTask.cancel(true) is invoked too late..... (even if I am not sure if cancel(true) will help)
So is this normal behavoiur with asynctask and backbutton?
This cant be normal, because how should the user ever get back from the activity on slow connection?
wait for timeout?
I am Begging for Help, cancel an async webrequest SHOULD be possible :)

when the user presses the back button during the doInBackground Method, the Keyevent is always dispatched AFTER my doInBackground method is finished.
No, this isn't true.
If I hit the BACK button on my device when an AsyncTask is running in my main Activity (downloading files from my server), the Activity is immediately closed.
What IS true, however, is the AsyncTask will continue to run whatever code is in its doInBackground() method UNLESS I explicitly cancel it (but you kind of know that already).
As far as I can tell, your 'webrequest' (whatever that may be) is blocking your doInBackground() method and because of that, any attempt to cancel it in onPause(), onStop, onDestroy() etc will never work.
As advantej points out, the way the AsyncTask.cancel(...) method works is that it causes isCancelled to be set to 'true'. In order to successfully cancel the AsyncTask's doInBackground() method you need to periodically check isCancelled. Example...
#Override
protected Void doInBackground(String... params) {
while (!isCancelled) {
DoSomething();
}
}
The problem is if DoSomething() (for example your 'webrequest') is blocking the while loop then isCancelled won't be checked until it completes.

This is the expected behavior. The documentation says :
Cancelling a task
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.)

Related

My AsyncTask starts after my Activity.onStop(), thus throws error because AsyncTask uses GoogleSignAPI

Since my Activity.onStop() gets called before the AsyncTask is finished, the GooglePlusAPI get disconnected in onStop(). I understand this is how a AsyncTask (Thread) should work, but is there any alternatively design I can do, so that I have a guaranteed GooglePlusAPI connection.
If you not want the AsyncTask running, call cancel() any time, like in Activity.onStop(). Also in the AsyncTask's doInBackground(), onPostExecute() and onProgressUpdate(), to add isCancelled() check before doing anything which my cause problem as activity stopped.

Android - Simple AsyncTask

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.)

Activity restart while async task is running

I'm confused with the async task. What do I have to do when my activity restarts?
In my activity, onCreate() starts an async task.
I know that the activity restarts when android requires it (i.e. orientation change or other).
I've no problem with this... and I think restarting a new async task is acceptable.
Nevertheless I don't know what's happening with my previous async task.
Do I have destroy it ?
My second question: what if I have a progressDialog in my previous task. Do I have to dismiss this dialog (and how)?
No, your Asynctask will end with your activity as well as your progressDialog. When your activity calls onRestart() it must first go through onPause and onStop which will destroy your activity but not your application.
For more information on activities - http://developer.android.com/reference/android/app/Activity.html
Additionally, it would be safer to cancel your Asynctask as well as set progressDialog to null.
From Asynctask documentation
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.)
you have to save the instance of activity and when your activity restart you have to resume your activity with that instance use this link: Saving some data on orientation change in Android
ya you have to dissmis that dialog.

android: cancel(true) does not kill the AsyncTask

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.)"

How to end AsyncTask onBackPress() and also does it still run if it isnt finished?

I use AsyncTask in several activities.
i know how to Override onBackPress().
But when an AsyncTask is running i want to give the user the ability to go back even though the asynctask is still running.
How can I do this?
Also does an asynctask still run when activity that initiated it is closed before it finishes?
AsyncTasks run on until they complete or are cancelled. So in your case (the user presses Back and you end the main activity), the AsyncTask will carry on.
If you did want to end the AsyncTask from onBackPressed, the best you can do is to call
myAsyncTask.cancel(true);
but all that does is call the task's onCancelled() which can set a cancel flag that can be checked (usually) in doInBackground() - and if it is set the task can return.
Note that using cancel(true) does not stop the task. The docs talk about "interrupting" the task for the true case, but all they mean is that onCancelled will be called while doInBackground is running - at which point the task has an opportunity to set a flag that doInBackground can inspect.
For the true case, if the task does not implement onCancelled, and/or it does not set/inspect a flag, the task will complete doInBackground, but onPostExecute(Object) is never invoked - which is equivalent to the false case.
The async task will continue to run even if your application was closed. You have to be careful with that since your task will leak your context (keep it in memory) if it has a reference to it (so the activity) as long as your task is still running. You can avoid that by referencing your activity by a WeakReference.
You can stop a running task with cancel(true). A cancel will let the task finish its doInBackground but will never call onPostExecute. You could interrupt your background routine by checking isCanceled() and so return earlier since the task was killed.
I deleted one half of my post!
I did so confuse interrupt with a thread stop! Using true will of course NOT stop the actual thread. Thanks a lot to Torid and his answer which proved me wrong! Big lesson lernt, thanks for that!

Categories

Resources