How to handle the termination of an app-wide polling-routine? - android

I have kind of a tricky situation in my app.
I implemented a mechanism that contacts a remote server every 60 seconds to check if new data is available. If so, the new data is displayed in the app. So far so good.
I implemented the mechanism the following way:
It gets started in the onCreate() method of my MainActivity.
The polling routine gets stopped in my MainActivity's onDestroy() method.
This makes sure the polling is always active as long as the app is running. Also, if I start another Activity from my MainActivity, I also want the polling to run.
My Problem:
When I exit my application via the Back-Button, everything works fine and the polling stops. But when I exit my application through the Home-Button, the polling routine stays alive since onDestroy() of my MainActivity is not called, but I want it to stop.
If I change my code and stop the polling routine in the onPause() method of my MainActivity, I have the problem that the polling also gets stopped when I launch a new Activity.
What I want:
I want the polling to run as long as my Application (not my MainActivity) is in foreground / visible to the user. As soon as the User exits the application by pressing the Home-Button from anywhere in the App, or by pressing the Back-Button from the MainActivity, I want the polling to stop.
ADDITIONAL:
I also do not want to restart and stop the service everytime I switch Activities. Since the user of my Application will switch Activitys very often, this would just be a lot of overhead. Furthermore, I want the "refresh"-cycle to be exactly 60 seconds. I cannot guarantee that when I always restart the service and stop it again. It needs to be started once when the app gets started, and stopped when the app is no longer in foreground.
How to achieve that?
Isn't there some kind of simple way to check when the App is in foreground and when its hidden / closed?
This is my singelton-polling mechanism:
private Timer t;
private static Updater instance;
protected Updater() {
// Exists only to defeat instantiation.
}
public static Updater getInstance() {
if(instance == null) {
instance = new Updater();
}
return instance;
}
public void startPollingRoutine(int interval, int delay) {
t = new Timer();
// Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
update(); // some asynctask that does the updating
}
}, delay, interval);
}
public static void stopPollingRoutine() {
t.cancel();
}
In code:
Updater.getInstance().startPollingRoutine(60000, 0);
Updater.getInstance().stopPollingRoutine();

I think the best way how to handle it is to create some BaseActivity which all activities will extend. And to perform this actions in onResume/onPause. Or you can try using services.

you need to create a service and trigger it in your main class that service will be triggered unless you explicitly stop it on destroy means onBackpressed()/onDetroy() and let it run in onPause() method

Use a singleton, and let it have a counter variable. Increase it when you send intent to start a new activity, and decrease it in the onPause.
Than you can tell if the polling has to stop; when the counter in the singleton is zero.

Thank you all for your help and time.
I finally found a solution by myself that meets all my requirements.
I followed this tutorial to make it work: http://www.mjbshaw.com/2012/12/determining-if-your-android-application.html
The basic Idea is to extend the Application class and keep reference to how many Activitys are "alive" at a certain time.

Related

Thread Continues to Execute After Closing the Application

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

Should I start/stop service in onStart/onStop, or onCreate/onDestroy

Currently, I have service, which runs in separate process. Here is the code in main activity.
#Override
public void onStart() {
super.onStart();
// Start auto complete service.
autoCompleteServiceIntent = new Intent(AutoCompleteService.class.getName());
startService(autoCompleteServiceIntent);
bindService(autoCompleteServiceIntent, serviceConnection, 0);
}
#Override
public void onStop() {
super.onStop();
// Stop auto complete service.
unbindService(serviceConnection);
stopService(autoCompleteServiceIntent);
autoCompleteServiceIntent = null;
}
The service will have the following characteristics.
The service runs in separate process. The reason is that, it will load a large data into memory. Having the service to run in separate process, will allow us to have larger memory limit.
Once main activity dead, the service shall dead too.
I was wondering, should I start/stop service in onStart/onStop pairs? Or, shall I start/stop service in onCreate/onDestroy.
The good thing I can think of, when having the code in onStart/onStop pairs is that, I can release unused memory immediately, whenever the activity is invisible. Hence, free up large system resource. Note, onDestroy is not always being called immediately, even the activity has quit.
The bad thing is, if I press HOME and come back frequently, my service will perform memory loading/unloading frequently. This may cause my application performs considerable slower.
In your scenario you should stop the service onDestroy the reason been is that, its called when the activity is destroyed self, foreclosed or by system when it needs memory. So that will be a appropriate place to end the service.
Where else onStop will be even called when you move back and forth in your application or visit home. The reason onDestroy is not called on home press is the activity is not destroyed yet. Where as if you close activity pressing back it will call onDestroy.

Android UI Update Thread - saving and restoring it

How do I properly do that?
I have a stopwatch and I'm saving it's state in onSaveInstance and restoring it's state in onRestoreInstance...
Now I've following problem: if I stop the thread in onSaveInstance and the screen get's locked or turned off, onRestoreInstance is not called and the stopwatch is not continuing...
If I don't stop it, the stopwatch is running in background on and on even when the screen is off or the activity is not active anymore...
So what's the usual way to handle such a thing?
PS:
I even have a working solution, a local variable to save the running state in the onStop event and restarting the thread in the onStart event... But I still want to know if there's a "default" solution using the android system itself....
Ok. I better now understand what you're doing. I thought you were using the thread to count. Right now it sounds like you're using it to update the UI.
Instead, what you probably should be doing is using a self-calling Handler. Handlers are nifty little classes that can run asynchronously. They're used all over the place in Android because of their diversity.
static final int UPDATE_INTERVAL = 1000; // in milliseconds. Will update every 1 second
Handler clockHander = new Handler();
Runnable UpdateClock extends Runnable {
View clock;
public UpdateClock(View clock) {
// Do what you need to update the clock
clock.invalidate(); // tell the clock to redraw.
clockHandler.postDelayed(this, UPDATE_INTERVAL); // call the handler again
}
}
UpdateClock runnableInstance;
public void start() {
// start the countdown
clockHandler.post(this); // tell the handler to update
}
#Override
public void onCreate(Bundle icicle) {
// create your UI including the clock view
View myClockView = getClockView(); // custom method. Just need to get the view and pass it to the runnable.
runnableInstance = new UpdateClock(myClockView);
}
#Override
public void onPause() {
clockHandler.removeCallbacksAndMessages(null); // removes all messages from the handler. I.E. stops it
}
What this will do is post messages to the Handler which will run. It posts every 1 second in this case. There is a slight delay because Handlers are message queues that run when available. They also run on the thread that they're created on, so if you create it on the UI thread you will be able to update the UI without any fancy tricks. You remove the messages in the onPause() to stop updating the UI. The clock can continue to run in the background, but you won't be showing it to the user anymore.
I just got into Android programming, but I don't think onRestoreInstance will be called in that situation because you're not switching from one activity to another. I think your best bet is to call onPause which will then call onSaveInstance if you need it to, but use onResume which might or might not call onRestoreInstance.

Android: How to backup a database when the application gets closed?

I am needing help to determine the right approach. I want to make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed. I want to call this method from a central class called Main which extends Application. The reason for that is, that I need to use several activites and I want to call the backup Method only when needed (like described when the whole application gets destroyed or interrupted by another application). I try to avoid calling this backup method in every activity in their onPause() methods.
I thought about starting a service in the onCreate() method of the application, and starting the backup method when the service gets destroyed. But this won't help in the case of an interrupt, as far as I understood the logic behind services. And also the service doesn't seem to start. startService(new Intent(getApplicationContext(), BackupService.class)); Furthermore I don't think it is a good approach to just use the onDestroy() method of a service, this is not what the service class is made for in my opinion.
So summarizing my Question, do you know a better way then using a service, or if not do you know how I should use the service to be able to call a backup only at the point when the whole app (and not only an activity) is interrupted or destroyed.
First of all, if your service "doesn't seem to start", you are probably doing something wrong.
To accomplish your goal make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed:
There are three cases in general here.
If you want to do it in the activity layer:
To know when your application is crashed, you need to implement a custom handler to catch the uncaught exceptions.
To know when your activity is "interrupted", the only way is do it in onPause.
To know when your activity is "terminated", the only way is to do it in onDestroy.
This will require you to have a clear navigation and only do it in your "main activity", and all the other activity starts and comes back to it OR use a flag to indicate if the pause was caused by going to another activity.
If you want to do it in the service layer: (Your way of doing it onDestroy won't allow you to detect interrupted case since you will have to start service sticky to keep it running)
You will have to set up a flag on each activity onBind (you will have to bind it and unbind it) to know if it is a crash/interrupt/termination, which will complicate other part of your code.
To avoid running repetitive code, you will have to create a generic base class and extend your other activities from it.
I use this approach to play background music in one of my games, but I guess it works in this scenario as well.
Use a boolean flag to indicate whether or not your app is launching another part of your app.
boolean movingInApp = false;
....
movingInApp = true;
Intent intent...
.....
public void onPause() {
if(!movingInApp) {
//start service
}
}
public void onResume() {
movingInApp = false;
//Stop service
}
By setting the value of movingInApp to true before launching any intent etc, you can prevent your app from starting the service. Remember to set it to false again later in your onResume() method. If the system makes your app go to the background, this will be false, and your service will be started.
Why dont u have all of your activities extend a base activity which in turn extend the android activity class
I the base activity have backupDB method in the onPause
Therefore u dont have to put it in every activity pause method

How keep a CountDownTimer running when I press the back button

I have a CountDownTimer which updates a TextView, but when I press the back button it stops.
CountDownTimer timer = new CountDownTimer(600000, 100) {
public void onTick(long millisUntilFinished) {
calendar.setTimeInMillis(millisUntilFinished);
cron.setText(sf.format(calendar.getTime()));
}
public void onFinish() {
}
};
How can I keep it running when I press the back button and the activity gets destroyed?
PS: I also start a GPS service when the timer starts, Is there a way to put the CountDownTimer in the service?
If your timer needs to live beyond the lifecycle of your Activity, then it does not belong there. You can certainly place it into a Service, or another object (like a singleton) that can stay resident in memory.
As prashant and Devunwire pointed out, you need to use a Service. Make sure you call startService() before binding to it, this causes the Service to stay alive even if the calling Activity is destroyed.
Make sure as well that the service stops itself with stopSelf() after the timer has finished and did whatever its supposed to do.
I think it should be possible to put the countdown timer in a Service. You can trigger the timer to start by sending an intent to the service. Also, you will have to use some mechanism such as a callback or intent or messenger to relay the update time back to your UI.
Override the back button and then make it behave like the home button. This way your activity is never destroyed. That said, I don't think this is considered "good practice."
To do what I'm saying you just place this into your activity class.
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
Whatever you do, as an optimization, you should make sure that the TextView is not updated if the TextView isn't visible on the screen. This should save battery life and probably prevent the creation of strings which will reduce garbage collections.

Categories

Resources