129

If my app is running and I press home button, the app goes in background. Now if I long press the home button and kill the app by swiping it from the recent app list, none of the events like onPause(), onStop() or onDestroy() gets called rather the process is terminated.

So if i want my services to stop, kill notifications and unregister listeners, how can I do that?

starball
  • 20,030
  • 7
  • 43
  • 238
CodeWarrior
  • 5,026
  • 6
  • 30
  • 46
  • I resolve my issue. [Check](http://stackoverflow.com/questions/26842675/continue-service-even-if-application-is-cleared-from-recent-app) – MysticMagicϡ Nov 12 '14 at 07:07
  • @MysticMagic That works for a Service, what about cancelling Notifications and unregistering listeners? – CodeWarrior Nov 17 '14 at 07:00
  • You can unregister listeners in onTaskRemoved. Can't you? And same for cancelling notifications – MysticMagicϡ Nov 17 '14 at 11:00
  • @MysticMagicϡ What If I want to do the same things on app update? – reji May 20 '15 at 06:24
  • Swiping up an app on the recent task list will cause the service's onDestroy to be called. You can place your cleanup code there. – Johann Apr 22 '21 at 07:19

9 Answers9

180

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 my question for more details, which contains other part of code, too.

starball
  • 20,030
  • 7
  • 43
  • 238
MysticMagicϡ
  • 28,593
  • 16
  • 73
  • 124
  • Thanks. Thinking if this method could be used to identify swipe kills. Simple blank service ? – kiranpradeep Nov 21 '14 at 08:36
  • @MysticMagicϡ but the onTaskRemoved sometimes called after onCreate when service starts again... http://stackoverflow.com/questions/32224233/ontaskremoved-called-after-oncreate-in-started-service-on-swipe-out-from-recent – umesh Aug 27 '15 at 07:55
  • 1
    @MysticMagicϡ hi, one question, I tried using your solution, but it seems long operations like sending data to server, analytics to google etc some times fail to go all the way through. Could it be that the process is killed before this method had a chance to fully complete itself? Also have you tried this method on an Huawei device? It seems onTaskRemoved never gets called on those devices. Any ideas why? – Alon Minski Dec 01 '16 at 08:08
  • is there any solution related to this same issue pointed here: http://stackoverflow.com/questions/40021274/ontaskremoved-of-a-android-service-is-never-being-called-why?noredirect=1#comment72416170_40021274 – android_sh Mar 07 '17 at 10:52
  • it's not stable https://stackoverflow.com/questions/45963407/service-ontaskremoved-or-ondestroy-very-rarely-being-called-on-swiping-app-off – user924 Aug 30 '17 at 20:21
  • so `onTaskRemoved` isn't called (only sometimes, rarely) and notification isn't being removed (server is still alive) – user924 Aug 30 '17 at 20:26
  • I'm testing on 6.0.1 Android – user924 Aug 30 '17 at 20:26
  • Hello bro not working for me you have any other solutions?? not get onTaskRemoved method log in logcat. – Pankaj Talaviya Apr 25 '18 at 06:33
  • 2
    @MysticMagicϡ public void onTaskRemoved(..) Method not call in Android O. Working fine in other OS but getting issue in Android O. – Jay Patel Apr 26 '18 at 06:42
  • this code is not working for oreo. is there any solution ? – Bineesh P Babu Dec 29 '18 at 06:07
  • @BineeshPBabu that's because there are restrictions for background services starting from Android O - https://developer.android.com/about/versions/oreo/background#services. This solution is no longer viable, this service will be stopped by system after a while – Vadim Kotov Jan 11 '19 at 15:16
  • Thanks `android:stopWithTask="true"` is worked for me. – Shailendra Madda Jul 05 '19 at 10:29
  • Any solution for Android O and Higher Version? – Ram Nov 22 '19 at 07:02
  • 3
    This code is not working for Android O because of background Service limitation. Is there any way to handle this in all Android devices? – Aanal Shah Feb 21 '20 at 05:15
  • Maybe you forgot to implement this method in service - @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("ClearService", "Service Started"); return START_NOT_STICKY; } – Taras Vovkovych Dec 02 '21 at 09:26
38

We need to create a service that would clear the application from recent service

public class ClearService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("ClearService", "Service Started");
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("ClearService", "Service Destroyed");
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.e("ClearService", "END");
        //Code here
        stopSelf();
    }
}
  1. register this service in manifest.xml
<service android:name="com.package.ClearService" android:stopWithTask="false" />
  1. Then start this service on your splash activity
startService(new Intent(getBaseContext(), ClearService.class));

And now whenever you will clear your app from android recent Then this method onTaskRemoved() will execute.

JANO
  • 2,995
  • 2
  • 14
  • 29
emilpmp
  • 1,716
  • 17
  • 32
20

I resolved similar issue. If you want after swiping from recent task and on next launch it to behave properly then follow below steps:-

1) Save process ID in shared preference:

SharedPreferencesUtils.getInstance().putInt(SharedPreferencesUtils.APP_PROCESS_ID, android.os.Process.myPid());

2) When application is launched from launcher after clear from recent task then do:

int previousProcessID = mSharedPreferencesUtils.getInt(SharedPreferencesUtils.APP_PROCESS_ID);

int currentProcessID = android.os.Process.myPid();

if ((previousProcessID == currentProcessID)) {
    // This ensures application not killed yet either by clearing recent or anyway
} else {
    // This ensures application killed either by clearing recent or by anyother means
}
Peter
  • 1,674
  • 4
  • 27
  • 44
Anshul Agarwal
  • 1,513
  • 13
  • 17
6

When you press home - onPause and onStop of your Activity is being called, so at this time you have to do all savings and cleanup, because Android platform doesn't further guarantee that onDestroy or any other lifecycle method would be invoked, so the process could be killed without any notification.

Desert
  • 2,293
  • 15
  • 16
  • 14
    Thanks for the suggestion,but i do not wanna kill my notifications, services and listeners, on `onPause()` and `onstop()` they need to be killed only when the user exits the app i.e. log out. – CodeWarrior Oct 25 '13 at 04:32
3

ViewModel.onCleared() can be useful, if the goal is to release some resource (perhaps a system running somewhere else on the network) when the user executes a surprise exit by swiping, rather than by pressing the "stop" or button. [This is how I originally arrived at this question].

Application doesn't get a notification, and Activity.onDestroy() gets called for configuration changes such as changes in orientation, so the answer isn't there. But ViewModel.onCleared gets called when the Application is swiped away (as well as when the user backs out of the activity). If the resource you want to use is associated with more than one activity in the stack, you can add reference counts or some other mechanism to decide if ViewModel.onClear should release the resource.

This is yet another of many good reasons to use ViewModel pattern

emilpmp
  • 1,716
  • 17
  • 32
Bob Cram
  • 145
  • 6
3

As Bob Cram mentioned in his answer, View Model's onCleared() method is the answer. It works in both cases :

  1. When the user removes the app by swiping the app from background.
  2. When the user clear all the app using the clear list button.

Service's onTaskRemoved() will work when the user swipes the app from the background, but will not work when the apps are cleared using the kill all button.

But the viewModel's onCleared() method works in both cases. You can use if to stop any ongoing process or clearing any task in the remote server.

 override fun onCleared() {
        super.onCleared()
        Log.d(TAG , "App Killed")
    }
Utkarsh Singh
  • 59
  • 1
  • 2
2

I don't really know why the above approaches are not working on my case even I set android:stopWithTask="false" that onTaskRemoved() not called.

Another good approach would be using AndroidViewModel. This one even works on the case when user exits the applcation on pressing back button.

Just bound ViewModel class to your MainActivity then do your task onCleared() callback.

Example:

public class MainViewModel extends AndroidViewModel {
    public MainViewModel(@NonNull Application application) {
        super(application);
    }

    @Override
    protected void onCleared() {
        // Do your task here
        Log.e("MainViewModel", "OnCleared mainViewModel");
        super.onCleared();
    }
}

then bound it to your MainActivity:

MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class);

~ Voila!

droidhs
  • 41
  • 5
  • it may not be working with the service approach because of Android O and above as mentioned by other commenters. This seems like an interesting solution to utilize view models for this. Does this still get triggered if the application is force killed (swiped on the app switcher screen)? edit: Bob's answer suggests it does work in these cases – William Reed May 20 '20 at 17:13
  • yes it works, that is the case which I encountered with – droidhs May 21 '20 at 19:53
  • @droidhs I am trying to save some data in SharedPreference in `onCleared()` but seems like saving data is not happening? Can you help me a better approach where I can save data in this method?? P.S. I am getting the logs in this but data is not saved. – Shubham Agrawal Sep 22 '20 at 09:49
  • The onCleared method gets called when the user swipes the app to kill it; however, inside that method I make a native call (to shutdown an audio driver), but I never return from native code. I don't know what guarantees there are for onCleared to complete before the app is completely destroyed, but clearly they are not absolute. (I don't have the driver sources so I can't find out how far I get.) – Timmy K Jan 29 '21 at 12:48
  • Using the back button and clearing a viewmodel should not be considered to be related. In a single activity app, you can have a single viewmodel shared among several "screens" (although only one activity exists). You don't want the viewmodel destroyed when switching from one screen to another when both of them use the same viewmodel. – Johann Apr 22 '21 at 07:35
0

You need to save your data when on onPause() is called. Look at this life cycle diagram: Android Developer

You can see that an app can be killed after onPause() or onStop().

Handle your data there and recover it in onRestart() \ onCreate().

good luck!

CodeWarrior
  • 5,026
  • 6
  • 30
  • 46
Yakir Yehuda
  • 650
  • 7
  • 23
0

This worked for me on android 6,7,8,9.

Make one service like this:

 public class OnClearFromRecentService extends Service {

 @Override public IBinder onBind(Intent intent) {
     return null; }

 @Override public int onStartCommand(Intent intent, int flags, int
 startId) {
     Log.d("ClearFromRecentService", "Service Started");
     return START_NOT_STICKY; }

 @Override public void onDestroy() {
     super.onDestroy();
     Log.d("ClearFromRecentService", "Service Destroyed"); }

 @Override public void onTaskRemoved(Intent rootIntent) {
     Log.e("ClearFromRecentService", "END");
     //Code here
     stopSelf(); } }

2) Register this service in manifest.xml:

<service android:name="com.example.OnClearFromRecentService"
 android:stopWithTask="false" />

3) Then start this service on your splash activity

 startService(new Intent(getBaseContext(),
 OnClearFromRecentService.class));
craigcaulfield
  • 3,381
  • 10
  • 32
  • 40
  • 3
    And why will your service keep running on Android 8 and above? You realise that there is restriction on Started Services post Android 8, right? – rahil008 Sep 24 '19 at 08:49