I want to know what is the best way to stop an async task frm running.
I have tried
#Override protected void onCancelled() {
super.onCancelled();
mTask.cancel(true);
}
I also tried
asyncTaskObject.cancel(true);
This works specially when associated with an event.
But suppose the scenario is--- there are 4 AsyncTask. First call the second, second calls the third and third calls fourth. When the user enters the activity there is no dialogbox.
Otherwise we could have used the onCancel method there.
When user clicks on anywhere on the page the dialog box appears if user does not click anywhere then no dialog box is shown but async task keep running in the background.Suppose the user clicks the "back" button on or the navigational icon to the home page user.is taken out of the current activity. But the async task keep running in the background and eventually the app crashes. I have used to the cancel method in onBackPressed. But the problem is you cannot be sure which task is running and app carshes again.
What is the way out of this?
keep reference to AsyncTask object as instance variable and then in onDestroy() do this
#Override
protected void onDestroy() {
if (mTask != null) {
mTask.cancel(true);
}
super.onDestroy();
}
In http://developer.android.com/reference/android/os/AsyncTask.html there's a session called Threading rules that say that AsyncTasks instances must be created on the UI thread and execute must be invoked on the UI thread. If you invoke execute from the UI thread you can cancel the thread calling yourTaskInstance.cancel(true);
I am not entirely sure when you want to cancel your tasks, but here are a few suggestions: a) keep a reference to each task that is running. b) add a dismiss listener to your dialog and cancel all tasks there (if that's what you want to do). c) cancel all tasks at the onStop callback of your activity (if that's what you want to do again).
Related
I want to specify an activity to be the loading activity for my app for some async Tasks .
it will be launched during in preExecute and will be finished in postExecute how to do that ?
#Override
protected void onPreExecute()
{
startActivity(new Intent(SearchActivity.this,LoadingActivity.class));
}
#Override
protected void onPostExecute(String result)
{
// i want to finish loading activity here.
}
That's just not how Android works.
There is always one Activity active at a time, and when you start an AsyncTask, you do so in the context of the current Activity.
So, while you technically could start an activity from the AsyncTask, it's parent context (the Activity that started the AsyncTask) would become inactive. The AsyncTask would continue to run (this is actually a big problem with AsyncTasks), but would likely crash - and even if not, the behavior would be undefined.
Shubham Nandanwar's answer looks like it should work, but is not the correct way to approach this. You should reconsider what you are trying to do in the context of the way that Activities and their lifecycles are supposed to work.
I'd suggest simply launching the Activity that you desire, and then use an AsyncTask in that activity to do whatever work needs to be done, and finish the activity from the activity itself when the work is done.
Better yet, find a better way to do background processing (e.g. RxJava), and do away with the AsyncTask.
I'm writing UI tests for my application using Espresso. I'd like to test the fact that if I click the back button while a server request is in progress the app must remain where it is.
It seems not to be possible due to the espresso's architecture that makes the tests execution wait if some background operation (like AsyncTask) has been fired.
So, how can I test the following scenario:
click on a button that fires an AsyncTask
test that while the task is running and I press back button, the app stays there?
Is it possibile?
thank you
That's tricky. With AsyncTasks you cannot use Espresso while the tasks are running.
And if you would use something else for background work, Espresso does not wait, and the test finishes before the background job.
A simple workaround would be to "press" the back button without Espresso while the task is running. So, start the task, call Activity.onBackPressed() and after the task finishes use Espresso to check that the Activity is still visible:
// Start the async task
onView(withId(R.id.start_task_button)).perform(click());
// Then "press" the back button (in the ui thread of the app under test)
mActivityTestRule.runOnUiThread(new Runnable() {
#Override
public void run() {
mActivityTestRule.getActivity().onBackPressed();
}
});
// Then check that the Activity is still visible
// (will be performed when the async task has finished)
onView(withId(R.id.any_view_on_activity)).check(matches(isDisplayed()));
You can prevent the application from triggering finish() when the back button is pressed. To do so, just override public void onBackPressed() without calling super.onBackPressed(). Just like :
#Override
public void onBackPressed() {
// super.onBackPressed();
}
Additionally, if you are showing a dialog while executing the task, you can use
myDialog.setCancelable(false);
myDialog.setCanceledOnTouchOutside(false);
to prevent the button from being pushed.
Regards,
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 have an AsyncTask running a loop which only stops looping when exiting the app, a global "stop" boolean gets set and it stops the loop and finishes through the AsyncTask.
I have this code:
#Override
public void onBackPressed()
{
KillAllThreads();
}
#Override
public void onUserLeaveHint()
{
KillAllThreads();
}
Now here is the thing. If I initiate the AsyncTask, onUserLeaveHint() gets called right away, and when the home button is pressed, it never fires this method. If I dont initiate the AsyncTask and let the activity load without doing anything, then when I press Home, it fires the onUserLeaveHint() method.
How am I supposed to stop the thread if the user clicks out of the app?
You should be able to call .cancel() on a AsyncTask, have you tried that?
Have a look at this sample project on my google docs, It illustrates the important aspects of AsyncTask:
starting a task, publishing progress, etc.
It shows how to cancel the running task.
It shows how to cancel a running task when your activity is paused or stopped.
link:
https://docs.google.com/leaf?id=0BwAnjRVwT4WzOWMwYjFhNTctOTUxYy00NjQwLTgwNWEtMmE5MzEyZWQ3NjUx&hl=en_US&authkey=CLnH8_ID
I have a START and STOP button in the main screen of an App. there are some GUI and threads that are instantiated when I click on START. When I click on stop, I want everything to be stopped and the activity should come back to its origin state. To the state that is exactly same like when launched (when we tapped on App icon in mobile).
Is it possible to do this? I tried with finish() , this killed the app and exited . I don't want to exit from main screen. rather, on clicking STOP I want app to come back to origin or born state. Thanks.
How are you running your threads? Are they vanilla threads or subclasses of AsyncTask?
If these are instances of an AsyncTask object, you can use the cancel() method to cancel it and then inside your doInBackground() method, you could check the isCancelled() method to see if it has indeed been canceled, and then exit gracefully.
Pseudo code below:
private YourTask taskRef;
public void btnStartHandler() {
taskRef = new YourTask();
taskRef.execute();
}
public void btnStopHandler() {
taskRef.cancel();
}
and then, in your AsyncTask:
public Void doInBackground(Void... arg0) {
// Background loop start
if (this.isCancelled()) {
return;
}
// Background loop continue...
}
If you're using threads, you can interrupt them and catch the exception and handle it there. Furthermore, you could create a method that you call from onCreate() called initApp() or something that initializes everything. You could also use that initApp() from the STOP button click handler to reset values back to startup defaults.
You can restart the activity with finish() and then call startActivity(getIntent());. This will effectively restart your activity and put it in its default state, no matter how it was started.
Before doing that make sure to cancel all threads or AsyncTasks as TJF suggested (you can and should do this in the onDestroy overload).
For more info about restarting an activity, and a discussion about pros and cons, see this question: Reload activity in Android