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.
Related
I have an Android existential question:
Does an App's onDestroy() get called when I kill it by swiping it out of the task manager?
If not... how can I detect a "killing" swiping event on the app, and do some final stuff beore it dies?
onDestroy()
Perform any final cleanup before an activity is destroyed. This can
happen either because the activity is finishing (someone called
finish() on it, or because the system is temporarily destroying this
instance of the activity to save space.
Note: do not count on this method being called as a place for saving data!
There are situations where the system will simply kill the activity's
hosting process without calling this method (or any others) in it, so
it should not be used to do things that are intended to remain around
after the process goes away.
Instead, rely on onPause() and onStop() to do any final work before your app goes out of view.
Is your main concern the "swiping" event or just saving data? :)
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
I'm developing an android app using bluetooth communication (using a propetary protocol) and I need to catch the moment when the app is killed.
I wanted to use the "onDestroy()" method but it isn't called every time the app is killed.
I noticed that it is called when I press the back button and, only sometimes, when I kill the app from the task manager.
The question is: How can I catch the moment before the app is killed?
Here is the code I tried to use:
#Override
public void onDestroy() {
sendMessage(msg);
Log.d("SampleApp", "destroy");
super.onDestroy();
}
#Override
public void finish(){
sendMessage(msg);
Log.d("SampleApp", "finish");
super.finish();
}
Unfortunately finish() is never called and onDestroy isn't called every time I close the app from the task manager.
How can I handle this?
As stated in the documentation here, there is no guarantee that onDestroy() will ever be called. Instead, use onPause() to do the things you want to do whenever the app moves into the background, and leave only that code in onDestroy() that you want run when your app is killed.
EDIT:
From your comments, it seems that you want to run some code whenever your app goes into the background, but not if it went into the background because you launched an intent. AFAIK, there is no method in Android that handles this by default, but you can use something like this:
Have a boolean like:
boolean usedIntent = false;
Now before using an intent, set the boolean to true. Now in your onPause(), move the code for the intent case into an if block like this one:
if(usedIntent)
{
//Your code
}
Finally, in your onResume(), set the boolean to false again so that it can deal with your app being moved into the background by a non intent means properly.
Your application will not receive any additional callbacks if the process it terminated by external means (i.e. killed for memory reasons or the user Force Stops the application). You will have to make do with the callbacks you received when you app went into the background for your application cleanup.
finish() is only called by the system when the user presses the BACK button from your Activity, although it is often called directly by applications to leave an Activity and return to the previous one. This is not technically a lifecycle callback.
onDestroy() only gets called on an Activity as a result of a call to finish(), so mainly only when the user hits the BACK button. When the user hits the HOME button, the foreground Activity only goes through onPause() and onStop().
This means that Android doesn't provide much feedback to an Activity to differentiate a user going Home versus moving to another Activity (from your app or any other); the Activity itself simply knows it's no longer in the foreground. An Android application is more a loose collection of Activities than it is a tightly integrated singular concept (like you may be used to on other platforms) so there are no real system callbacks to know when your application as a whole has been brought forward or moved backward.
Ultimately, I would urge you to reconsider your application architecture if it relies on the knowledge of whether ANY Activity in your application is in the foreground, but depending on your needs, there may be other ways more friendly to the framework to accomplish this. One option is to implement a bound Service inside of your application that every Activity binds to while active (i.e. between onStart() and onStop()). What this provides you is the ability to leverage the fact that a bound Service only lives as long as clients are bound to it, so you can monitor the onCreate() and onDestroy() methods of the Service to know when the current foreground task is not part of your application.
You might also find this article written by Dianne Hackborn to be interesting covering in more detail the Android architecture and how Google thinks it ought to be used.
I just resolved a similar kind of issue.
Here is what you can do if its just about stopping service when application is killed by swiping from Recent app list.
Inside your Manifest file, keep flag stopWithTask as true for Service. Like:
<service
android:name="com.myapp.MyService"
android:stopWithTask="true" />
But as you say you want to unregister listeners and stop notification etc, I would suggest this approach:
Inside your Manifest file, keep flag stopWithTask as false for Service. Like:
<service
android:name="com.myapp.MyService"
android:stopWithTask="false" />
Now in your MyService service, override method onTaskRemoved. (This will be fired only if stopWithTask is set to false).
public void onTaskRemoved(Intent rootIntent) {
//unregister listeners
//do any other cleanup if required
//stop service
stopSelf();
}
Refer this question for more details, which contains other part of code, too.
Start service like below
startService(new Intent(this, MyService.class));
Hope this helps.
I am trying to figure out how Android works when it comes to lifecycle issues.
I have decided to have a long-running Service to hold my TCP-connections and other stuff.
I have one Activity, StartupActivity. That Activity starts a service, and then I press a button to Finish the Activity. I then launch the same app/Activity again, and thus the startService is executed again.
However, I expected the Service to still be alive (there has been no onDestroy called), but the onCreate-method in the Service is still being executed.
Why?
STEP 1: onCreate in StartupActivit is executed:
#Override
protected void onCreate(android.os.Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.startup);
startService(new Intent(StartupActivity.this, SamcomService.class));
registerReceiver(connectionReceiver, new IntentFilter("STARTUP_PROGRESS_MESSAGE"));
registerReceiver(connectionReceiver, new IntentFilter("STARTUP_FINISH"));
final Button button = (Button) findViewById(R.id.buttonExit);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
finish();
}
});
}
STEP 2: I press the button, and Activity.finish() is called (I am returned to the home screen)
STEP 3: I launch the app again, and the onCreate for the Activity is once more executed, thus starting the same Service
Now, when I start the app the second time the Service should be running (how do I check that?). I havent seen the Toast that is displayed when the Service onDestroy is called, and I also see the Notification that the Service creates (and removes onDestroy).
However, the onCreate is executed a second time. Do I now have more than one Service running at the same time?
However, the onCreate is executed a second time. Do I now have more than one Service running at the same time?
No, and I know this is confusing, but the startService() method does not start the service. It will be called in the service everytime you run it. For instance, if the service isn't started, it will start it and then run it. If the service is started, it will just run it. The android documentation says it was designed this way so that the startService() method is the easiest way to communicate with your service.
STEP 2: I press the button, and Activity.finish() is called (I am returned to the home screen)
This depends on if your service is running on the same process as your activity or not. If you have :process = "something" in your service declaration in the manifest, and you did everything else perfectly, the service is in another process and there are only three situiations inwhich your service will be destroyed. 1, your activity is destroyed(Almost guaranteed not to happen as your process has its activities active priority), 2, There is EXTREMELY low memory, 3 the service calls selfStop().
Since finish() does not destroy your app(Android keeps it around in memory encase the user comes back to it), your service is either just paused(If it was in the same process) or still running(If it was in a different process). Regardless another call to startService() will restart it if it was paused and run the service's startService method. You only ever have one of your services around.
I've got a service that is running in a separate process. I'm finding that after the main process UI thread exits from onDestroy() that my service is being destroyed even though I've provided the application context with the binding and specified BIND_AUTO_CREATE.
In my main process' UI thread onCreate() I've got this binding code:
Intent intent = new Intent(mAppContext, MyService.class);
mAppContext.bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);
In my main process' UI thread onDestroy() I've got this unbinding code:
mAppContext.unbindService(mMyServiceConnection);
Note that I never call stopService().
Android's documentation for bindService() says:
The service will be considered required by the system only for as long as the calling context exists.
If I'm reading that correctly, because I supplied the application's context, the service is considered required by the system for the life of the application.
I have thought that maybe the application's context dies with onDestroy(). This is what Android's documentation says for getApplicationContext():
Return the context of the single, global Application object of the current process.
If the application's context dies with onDestroy(), then I think Android has a big issue. The issue is that when the display is rotated, onDestroy() is called (and immediately followed by onCreate()). Thus the effect is that when the display is rotated -- and it occurs quite frequently in my case! -- my service always exits.
Note that the pid of my app's process never changes, i.e. it is the same process. That is important in light of the documentation for getApplicationContext() stating "current process."
Here are what my debug logs show:
04-03 05:15:12.874: DEBUG/MyApp(841): main onDestroy
04-03 05:15:12.895: DEBUG/MyApp(847): service onUnbind
04-03 05:15:12.895: DEBUG/MyApp(847): service onDestroy
04-03 05:15:12.934: DEBUG/MyApp(841): main onCreate
04-03 05:15:12.966: DEBUG/MyApp(847): service onCreate
04-03 05:15:12.975: DEBUG/MyApp(847): service onBind
So my questions are:
1) Is my understanding about binding/unbinding correct?
2) Is there a way to have my service not get destroyed when UI thread's onDestroy() is called?
A hack for question #2 is to never unbind. But I don't like it because then I am leaking a binding every time onDestroy() is called. I could "remember" that I've got one leaked binding, and leak just that one, but then I've got cascaded hacks and it's real ugly.
1) Yes, I think your understanding is correct (I say I think because I think I understand what you're saying ;-) ). The flag you are using means "start this service automatically if somebody tries to bind to it and keep it running as long as somebody is bound to it, but once nobody is bound to it, feel free to kill it".
2) Check out the START_STICKY flag as described here. That should allow you to start the service and keep it running regardless of what happens to the calling Context
In general, onDestroy() means your activity is about to be killed. When you rotate the display, the Activity is killed and recreated. You are responsible for saving any state to the Bundle in the appropriate method and then restoring it in onCreate().
Does your service get killed:
if there is a second Activity on the stack?
if you handle configuration changes?
Why do you need your service to stay alive after your application has been destroyed?
I think the general rule of thumb is that you can't be sure when your activities and services will be killed. If this is blocking something you're trying to achieve, there may be a clever way around it.
Edit - you can actually handle the orientation configuration change so that your activity isn't restarted. For more info see the second half of this answer.
About the "second" Activity: Image you start activity A and then activity B. Now you rotate the screen while B is showing, causing B to restart. Will A be restarted at this point? I'm not sure, but I have a hunch that A will tend to stay alive and keep your application alive during the orientation change. This might be another strategy for keeping your service alive if that's what you're aiming for.
a service is destroyed only when both of the following are true:
All calls to bindService() have been matched by corresponding calls to unbindService().
If somebody called startService(), somebody also called stopService() or the service called stopSelf().
A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated.
this gives a great solution which is also fairly correct and safe!
say there are 2 activities ('viewer' and 'chat' in this example) that need a service, if both bindService AND startService. Also using the binder they update 'viewer_connected' and 'chat_connected' during onStart and onStop.
Then the service runs a loop in a thread that does this:
public isRunning = true;
while (isRunning) {
if (viewer_connected) {
// send update to viewer activity
}
if (chat_connected) {
// send update to chat activity
}
try {
Thread.sleep(5000);
} catch (Exception e) { isRunning=false; }
// 3 second timeout before destroying service
if (!viewer_connected && !chat_connected) {
try { Thread.sleep(3000); } catch (Exception e) { isRunning=false; }
if (!viewer_connected && !chat_connected) isRunning=false;
}
}
stopSelf();
This works because it needs both the activities to unbind AND the service to stopself() before it destroys the service, meaning there is a timeout before the service gets destroyed.