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,
Related
I have an android application that uses Threads. Application waits for some time, then executes a function.
Things go pretty well if user waits for some time. After the predefined time t ends, the function gets executed.
However, if the user clicks on back button of the device and return to main screen, after the time t ends, the application appears again.
How can I understand if the user pressed back, or closed my application? How can I stop the thread and release everything if I get the leaving message -let's say USER_EXITED?
in your activity when the activity is going to end you can check if it is finishing like this and take care of things to do with your threads
#Override
public void onPause() {
if(isFinishing()){
//put the correct checks or shutdowns
{
super.onPause();
}
I think that you need to create a Service.
http://developer.android.com/reference/android/app/Service.html
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).
I Want to stop all the async tasks on the device home button press, but the problem is when progress dialog is running, on home button click only the progress dialog kills and it does goto the onKeyDown() method where i have mentioned the logic to kill my async tasks. So async task runs in the background even after the application is closed and my app crashed. Is there any solution to close the progress dialog as well as all async tasks on home button click
You can't intercept calls to the home button directly.Though when the home button is pressed onPause() will be called, so you can override that method and put your logic there.
Check out http://developer.android.com/guide/topics/fundamentals/activities.html#Lifecycle for more info
In java, we can't stop a Thread which has been started and is running. So is the AsyncTask
but you can try call asyncTask.cancel() which works like thread.interrupt(). It may throw an InterruptedException. If there exists more code behind, these code will execute as well, so take care of it.
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