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
Related
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,
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 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 two static tables with about 500 records each which provide lookup material for some ListViews in my app. When the app first starts and the tables are created I run a process to populate the tables which takes less than a minute but I've been looking to run the process in background using Async Task with a progress dialog letting the user know what is happening.
My concern is that while the process is running and the data is being added and then the user tilts the phone the process will cancel. What would be the state of my database then? Is Async Task the best solution for this or should I use Threading?
So when you rotate or change the orientation of the phone, the activity is the only thing destroyed. You don't necessarily have to get rid of the async task. In fact it will live on. Just don't let another task come in and work on it ad-hocly.
So if you want to have your activity act as if upon rotating that you can start right back up, where you left off, there is a method called onRetainNonConfigurationInstance(). It's basically the method that stashes objects which can't be parceled like in saveInstanceState()
So the idea being:
public void onCreate(Bundle a) {
...
AsyncTask myTask = getNonConfigurationInstance();
if (myTask == null) {
myTask = new AsyncTask();
myTask.execute();
}
...
}
public Object onRetainNonConfigurationInstance() {
return myTask;
}
This will keep the async task running, and when you get your onCreate called after the rotation you just pick it back up and do what needs to be done.
One thing to be conscious of is the progressView. It will have to be destroyed and reinitialized to the new state. Also the overall dismissing of it and showing it in the first place should be done outside the AsyncTask. But nothing is to say that the AsyncTask can't call some callback that you always set in your onCreate() so that it will notify to tell to update the UI or play a sound of completion, etc.
You could also decide to handle the configuration changes on your own through the use of the android:configChanges in your manifest.
You then implement the onConfigurationChanged method and perform any actions inside.
See the developer doc.
When a configuration change occurs at
runtime, the activity is shut down and
restarted by default, but declaring a
configuration with this attribute will
prevent the activity from being
restarted. Instead, the activity
remains running and its
onConfigurationChanged() method is
called.