简体   繁体   中英

How to handle running service when app is killed by swiping in android?

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?

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.

Hope this helps.

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();
}

}

2)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.

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
}

当你按下 home 键时 - 你的 Activity 的onPauseonStop正在被调用,所以这个时候你必须做所有的节省和清理,因为 Android 平台并没有进一步保证onDestroy或任何其他生命周期方法会被调用,所以这个过程可以在没有任何通知的情况下被杀死。

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.

-- Bob

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!

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!

You can't handle swipe, because system just removes your process from memory without calling any callback.

I have checked, that before user calls "recent apps" screen, onPause() will be always called. So you need to save all data in onPause method without checking isFinishing().

To check back button, use onBackPressed method.

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")
    }

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));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM