18

I am working on a project, where while being on a specific Activity we show a local sticky notification. That should also be the case when the app is minimized. What I have to accomplish is to remove the local notification whenever the app is killed (by Android, because of memory lack or by the user, with a swipe from the recent apps list).

Usually onDestroy would be called whenever Android takes the Activity to open some space. That is fine in one of the cases, however swiping an app from the recent app lists doesn't call the onDestroy and the sticky notification stays.

What I did is, I implemented an empty Service which would force the onDestroy when the app is killed (both swipe and system kill) so I can get my notification removed.

However, what I would like to do is to differentiate between the swipes and system kill.

Is this even possible?

Nikola
  • 2,093
  • 3
  • 22
  • 43
  • 1
    Be warned: The behaviours you are describing have evolved. They are different in different versions of Android. Just because something works on one version (or on one device) does not mean that it will work the same on another version (or another device). – David Wasser Jun 19 '15 at 13:49
  • See http://stackoverflow.com/questions/20677781/in-android-4-4-swiping-app-out-of-recent-tasks-permanently-kills-application-wi as an example – David Wasser Jun 19 '15 at 15:19
  • @DavidWasser I have no problem getting to `OnDestroy()` or whatsoever, my question is, is it possible to differentiate between a swipe kill and a system kill. I don't have a service to preserve or any information. I just want to know which event lead to killing the application. But as I am reading more and more, it seems that it is not possible – Nikola Jun 19 '15 at 15:27
  • What about having a listener to the `Home` button so that if it is `long pressed,` you assume if the `activity` is killed within 10 seconds, it was swiped? – Steven_BDawg Jun 20 '15 at 17:49

7 Answers7

22

In general, if Android wants to kill your application because it has been in the background for too long (or because it wants to reclaim resources), Android will just simply kill the OS process hosting your app. It will not call finish() or onDestroy() on any Activity or Service components. The behaviour of "swipe from recent tasks list" has changed over time and is different in different Android versions. Someone should write a book about that :-(

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • 2
    From the docs for `OnDestroy()`: `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.`. If Android kills my activity it _should_ call `onDestroy()` – Nikola Jun 19 '15 at 14:09
  • 10
    No. Sorry. The documentation is wrong. Android doesn't kill activities. It kills entire processes. Trust me on this. – David Wasser Jun 19 '15 at 14:40
  • 3
    In the documentation of `Activity` there is table describing the lifecycle callbacks. In that section you will also see this: _"Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may killed by the system at any time without another line of its code being executed."_ Android can kill your process at any time after calling `onPause()` (Android version < 3.0) or `onStop()` (Android version >= 3.0) – David Wasser Jun 19 '15 at 14:58
  • But the fact it's `OnPause()` on api < 3.0 and `OnStop()` doesn't mean that `OnDestroy()` is not going to be called. In the same table, next for `OnStop()` is `OnDestroy()`. Lets assume API doesn't matter as we figuratively will target min API 18 – Nikola Jun 19 '15 at 15:26
  • No, you are missing the point. The documentation states that the app can be killed at any time after `onStop()` has been called, without a single line of code being executed. It doesn't explicitly say that `onDestroy()` will not be called, but that's exactly what it means. On API 18, `onStop()` is the last call that is guaranteed to happen. – David Wasser Jun 19 '15 at 15:37
  • @DavidWasser in the documentation it says: "If the user leaves a task for a long time, the system clears the task of all activities except the root activity. When the user returns to the task again, only the root activity is restored." That means activities can indeed be killed separately no? https://developer.android.com/guide/components/activities/tasks-and-back-stack.html#Clearing – Damnum Apr 20 '17 at 08:09
  • 1
    @Damnum As I said in my comment above, the documentation is wrong (or at least, it is not specific about how it "clears the task of all activities"). It even says "...the root activity is **restored**". If it had cleared only all the other activities, it would not need to **restore** the root activity. In actual fact, Android does not clear activities to recover memory. It simply kills the OS process hosting the application if the task has been idle for "too long" (however that is determined). Trust me on this. – David Wasser Apr 20 '17 at 08:17
  • @DavidWasser my problem right now is, my activity B (not launch activity) is open and user presses the home button. Later, Android kills the whole app process because of memory shortage. When I start the app again, activity B is started, instead of launch activity A. I wonder how this is possible, does Android remember the activity state even though the process is killed? I started a bounty here: http://stackoverflow.com/q/12363375/888881 you seem to have a lot of knowledge there, maybe you could take a look? thanks! – Damnum Apr 20 '17 at 08:25
  • 1
    Sorry after more research, I found the answer to my question here: http://stackoverflow.com/q/11365301/888881 (which was also from you :D ), thanks! – Damnum Apr 20 '17 at 09:18
  • `Android will just simply kill the OS process hosting your app. It will not call finish() or onDestroy()` - that's why we have to use service in foreground mode if we don't want android os kill our data (if we have some important data that should be saved before app fully destroyed) – user924 Aug 30 '17 at 13:11
3

You can check for when the user swipe-closes the app by adding a service to your app, and implementing the onTaskRemoved method: https://stackoverflow.com/a/26882533/2441655

Community
  • 1
  • 1
Venryx
  • 15,624
  • 10
  • 70
  • 96
2

This is a comment I found in reddit that seems to me really interesting:

Swiping an app away will effectively "kill" most apps. You can test this out using ADB if you have the SDK installed. Swipe everything out of your recents list, then launch the browser.

Use ADB to run 'ps' on the device and verify that the com.google.android.browser process is running. Go to the home screen, it's still running. Launch some other apps, and the com.google.android.browser process is still there.

Swipe it out of the recents list, however, and the process is gone. You can create a test app to further verify, and log the onDestroy() call in your Activity. It's not called when you back or home out of the app, or when you launch other apps. It does get called when you swipe the app out of the recents list though. I do agree that the recent apps list isn't really "multitasking".

The apps in the list aren't necessarily even running, the processes could have been killed by the memory manager long before you try to re-open it. However, you can't argue that the only purpose is to jump quickly to other apps when the swiping makes the actual process go away.

This is another good answer about what happen when you swipe an app out of the recent apps list. But the part that I liked most was:

Actually, removing an entry in recent tasks will kill any background processes that exist for the process. It won't directly causes services to stop, however there is an API for them to find out the task was removed to decide if they want this to mean they should stop. This is so that removing say the recent task of an e-mail app won't cause it to stop checking for e-mail.

If you really want to completely stop an app, you can long press on recent tasks to go to app info, and hit force stop there. For stop is a complete kill of the app -- all processes are killed, all services stopped, all notifications removed, all alarms removed, etc. The app is not allowed to launch again until explicitly requested.

Community
  • 1
  • 1
Jorge Casariego
  • 21,948
  • 6
  • 90
  • 97
  • @Mero has already posted this reddit comment, but it has been posted 3 years ago.. Since then things have changed... I am aware of how those two work, point is, how to differentiate between swipe kill and system kill? – Nikola Jun 19 '15 at 14:07
0

By Swiping from recent task list removes only from recent tasks .. It was also called onDestroy before android 5.0 . Might be you are having issue above api level 20 devices. System kill normally can not be executed in normal android activity lifecycle. It just finishes the activity on back press event.

Nilay Dani
  • 896
  • 6
  • 24
  • `OnDestroy()` is not being called on Android 4.4.4 I am using, but that is not the matter. I force `OnDestroy()` by having my empty service. Question is, can I differentiate between swipe kill and system kill? – Nikola Jun 19 '15 at 14:10
0

when swiping app to left if any Thread still run in your app Interrupted but service not stopped, when you kill handy app Thread and services are stopped.

Ehsan Jelodar
  • 1,544
  • 19
  • 25
  • I am never killing the app, I am trying to figure out how to detect if it is rather a swipe kill or Android has taken my activity (while in the background) – Nikola Jun 19 '15 at 14:07
  • i research to android documentation but not found any difference between auto "system kill" and "swipe kill", also [this](http://stackoverflow.com/a/5862048) link maybe helpful. – Ehsan Jelodar Jun 19 '15 at 15:38
0

the behavior is similar to but not exactly the same as closing an app -- in general (for apps that don't define explicit back button handling) it's the same thing as hitting back enough times from within an application that you exit out of it.check out this link discussion it has some good input on the subject

Mero
  • 622
  • 12
  • 24
0

First, let's get one thing clear: Android MAY NOT CALL onDestroy(). Referring to the Activity Page, from Honeycomb onward, onPause() and onStop() are guaranteed to be called before an app is killed.

Be aware that these semantics will change slightly between applications targeting platforms starting with HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts when onSaveInstanceState(Bundle) may be called (it may be safely called after onPause() and allows and application to safely wait until onStop() to save persistent state.

So after (hopefully) clearing the air on the Android lifecycle, I think you can achieve what you want by putting the notification removing code in onStop() instead. If you end up needing it back because the user actually DOES come back to the specific Actvitiy(IE not killed), you can bring it back in onRestart().

Steven_BDawg
  • 796
  • 6
  • 21
  • 2
    I do not want to use `OnStop`, because I want to application to be run on the background (for as long as it can, before it is killed) by not using a service. I am aware of the fact `OnDestroy` is not always called, thus I have implemented an empty `Service` to force it. – Nikola Jun 19 '15 at 14:05
  • Okay I understand now. I apologize. If your service is called by both events (Android system and user-app-swipe), I'm not sure there's a way to determine 100% the difference between the two. You could write a `listener` for the `Home` button that, if it's long pressed, you would know about it... Like I said though, that doesn't necessarily 100% catch the correct event. – Steven_BDawg Jun 19 '15 at 14:38