Android app doesn't call "onDestroy()" when killed (ICS)
Asked Answered
M

3

24

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?

Munshi answered 13/7, 2012 at 15:45 Comment(4)
Do you mean when the app is killed by the system, when the user presses Force Stop in settings, or just when the HOME or BACK button is pressed while looking at your Activity?Crocus
Both of them are ok for me, I would like to catch the moment when the user kills the app from the task manager (or long-press the homescreen and kills the app from there, in Ice cream sandwich) but it's ok also catching the moment when the user presses HOME or BACK button looking at my activity.Munshi
Did u solve it?Ge
Yes, with the solution below..Munshi
M
17

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.

Morbid answered 13/7, 2012 at 15:51 Comment(3)
I already read it but the problem is that if I put my code in the onPause() it will be executed also if I start a new intent in my app. Instead I'd like to send my message only when the onPause is called to go back to the home screenMunshi
Only the homescreen, or another app like when a call comes in, or the user views a notification?Morbid
let's say I'd like to know whenever my app is no more displayed (so it goes in background for whatever reason), but I don't want to do anything when an intent is started because I started a new intent from my appMunshi
C
16

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.

Crocus answered 13/7, 2012 at 16:11 Comment(2)
I think this is more proper way, I think also he should add an interface(or abstract class) in application to enforce newly added activities(or components) to define behavior for this.Federalist
developer.android.com/guide/components/activities/…Steading
N
5

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:

  1. Inside your Manifest file, keep flag stopWithTask as false for Service. Like:

    <service
        android:name="com.myapp.MyService"
        android:stopWithTask="false" />
    
  2. 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.

  1. Start service like below

startService(new Intent(this, MyService.class));

Hope this helps.

Nikolas answered 16/11, 2017 at 8:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.