33

I am starting a service (or re-starting the running service) when an activity is launched, using :

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

Later on based on certain actions, the same activity binds to the service using

bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);

And when the activity is destroyed, I call

unbindService(mConnection);

Earlier, the service used to restart when I killed the same activity/application from the application tray and showed the "message 1 process 1 service running" under running apps.

Now, the service does not restart on killing the same activity/application.

And I get the message "0 process 1 service running", which means the service is actually not running.

The service does not restart on application being closed. My application consists of one activity. Also the service is successfully started when launched after a system boot.

Why does the process of the service gets killed when I start it using startService() ??

edit

The service used to re-start earlier after i closed the app from the application tray. But now suddenly with the SAME code, it doesn't. It happens with other apps too when i close them. eg.

enter image description here

geekoraul
  • 2,623
  • 2
  • 21
  • 33
  • 1
    I've reported a similar (but not exactly the same) issue and workarounds here: [Issue 178057: Process killed when task removed while bound to service with BIND_AUTO_CREATE flag](https://code.google.com/p/android/issues/detail?id=178057). You can vote for it to try to get it fixed. – Sam Jun 24 '15 at 11:17
  • What did you mean by **Earlier, the service used to restart**? How earlier. – IgorGanapolsky Aug 29 '17 at 17:24

6 Answers6

59

Here is a workaround I came across and works well for re-starting a service if its process is killed on closing the application. In your service, add the following code.

I came across this workaround in this thread.

@Override
public void onTaskRemoved(Intent rootIntent){
    Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
    restartServiceIntent.setPackage(getPackageName());

    PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmService.set(
    AlarmManager.ELAPSED_REALTIME,
    SystemClock.elapsedRealtime() + 1000,
    restartServicePendingIntent);

    super.onTaskRemoved(rootIntent);
 }

Seems to be a bug that the process of the application is killed. There is no point for a service to run if its process is killed.

geekoraul
  • 2,623
  • 2
  • 21
  • 33
  • 4
    When I swipe an application out of the application tray "onTaskRemoved" call back getting called but service is not starting why? – Prashanth Debbadwar Jan 22 '16 at 06:05
  • @geekkoraul it does not work for, is there any change in android 5.0?? – abhishek Mar 11 '16 at 14:09
  • excellent solution, best way to force start service when closed +1 man – Michael Sep 29 '17 at 15:27
  • 2
    but when i kill the application like one plus x phone this onTaskRemoved method doesn't call so that this is not working for me and this happened for most of the phone. – pavel Aug 22 '18 at 17:40
8

Please be aware of that: onDestroy is not always called. You should not put code that way.
When activity forced closed or closed by system abnormally, onDestroy is not getting called.

Nick Jian
  • 457
  • 4
  • 12
7

Unfortunately, this is a complicated problem due to the way Android works. There are a number of strategies that each work around different parts of the problem. For best results, combine multiple strategies together.

Note that some of these strategies may no longer be necessary in more recent Android versions.

1. Start an activity

What to do

Taken from Foreground service killed when receiving broadcast after acitivty swiped away in task list:

In the foreground service:

  @Override
    public void onTaskRemoved( Intent rootIntent ) {
       Intent intent = new Intent( this, DummyActivity.class );
       intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
       startActivity( intent );
    }

In the manifest:

  <activity
    android:name=".DummyActivity"
    android:theme="@android:style/Theme.NoDisplay"
    android:enabled="true"
    android:allowTaskReparenting="true"
    android:noHistory="true"
    android:excludeFromRecents="true"
    android:alwaysRetainTaskState="false"
    android:stateNotNeeded="true"
    android:clearTaskOnLaunch="true"
    android:finishOnTaskLaunch="true"
    /> 

(If your service is in a different process then set this activity's process to the same one.)

In DummyActivity.java:

  public class DummyActivity extends Activity {
        @Override
        public void onCreate( Bundle icicle ) {
            super.onCreate( icicle );
            finish();
        }
    }

Side effects

Causes the recents activity to close. Normally, swiping away an app doesn't close the recents activity.

Disadvantages

This only takes effect when the dummy activity starts, which may take half a second or more, so this still leaves the service open to being killed for a bit.

Explanation

When you remove/swipe your app away, a flag called waitingToKill is set. While this flag is set, Android may kill the process at any point in the future, such as when you receive a broadcast. Starting an activity clears this flag.

2. Spam a BroadcastReceiver with foreground broadcasts

What to do

Merge this into your service code:

if (Build.VERSION.SDK_INT >= 16) {
    Intent intent = new Intent(this, DummyReceiver.class);
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

    //This seems to be timing-related; the more times we do this,
    //the less likely the process gets killed
    for (int i = 0; i < 50; ++i)
        sendBroadcast(intent);
}

Create a dummy broadcast receiver:

public class DummyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {}
}

Add the receiver to your manifest:

<receiver android:name=".DummyReceiver" />

Side effects

May cause a slight (~250ms) delay/hang when the task is removed from the recents screen.

Disadvantages

This only keeps the process alive while it is receiving the broadcasts. the waitingToKill flag is still set, so the process may still be killed afterwards, such as when a broadcast is received.

Explanation

If your process isn't running in foreground priority, Android will try to kill it immediately. Receiving foreground broadcasts temporarily prevents this, resulting in the waitingToKill flag being set instead.

3. Don't bind to services

Binding to a service seems to increase the likelihood of the service's process being killed immediately when a task is removed.

Sam
  • 40,644
  • 36
  • 176
  • 219
1

I know this question is old but I recently encountered this problem and suddenly my service get stopped on closing app. Earlier it was working fine. This problem wasted my lot of time. To others who have similar problem make sure that YOUR BACKGROUND DATA RESTRICTION IS OFF. This was the problem I had and it actually makes sense as when background data is Restricted background process won't run.

lego king
  • 558
  • 5
  • 11
1

onDestroy is not always called. The Main problem in your case is ur unable to start the service when app closed,that time android OS(In Some OS) will kill the service, If you are not able to restart the service then call a alarm manger to start the reciver like this,

Manifest is,

         <service
            android:name=".BackgroundService"
            android:description="@string/app_name"
            android:enabled="true"
            android:label="Notification" />
        <receiver android:name="AlarmReceiver">
            <intent-filter>
                <action android:name="REFRESH_THIS" />
            </intent-filter>
        </receiver>

IN Main Activty start alarm manger in this way,

String alarm = Context.ALARM_SERVICE;
        AlarmManager am = (AlarmManager) getSystemService(alarm);

        Intent intent = new Intent("REFRESH_THIS");
        PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);

        int type = AlarmManager.RTC_WAKEUP;
        long interval = 1000 * 50;

        am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);

this will call reciver and reciver is,

public class AlarmReceiver extends BroadcastReceiver {
    Context context;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;

        System.out.println("Alarma Reciver Called");

        if (isMyServiceRunning(this.context, BackgroundService.class)) {
            System.out.println("alredy running no need to start again");
        } else {
            Intent background = new Intent(context, BackgroundService.class);
            context.startService(background);
        }
    }

    public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        if (services != null) {
            for (int i = 0; i < services.size(); i++) {
                if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
                    return true;
                }
            }
        }
        return false;
    }
}

And this Alaram reciver calls once when android app is opened and when app is closed.SO the service is like this,

public class BackgroundService extends Service {
    private String LOG_TAG = null;
        
    @Override
    public void onCreate() {
        super.onCreate();
        LOG_TAG = "app_name";
        Log.i(LOG_TAG, "service created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(LOG_TAG, "In onStartCommand");
        //ur actual code
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Wont be called as service is not bound
        Log.i(LOG_TAG, "In onBind");
        return null;
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.i(LOG_TAG, "In onTaskRemoved");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(LOG_TAG, "In onDestroyed");
    }
}
Community
  • 1
  • 1
Ajith K P
  • 398
  • 3
  • 12
0

when there is no binding to a service or well established foreground then android system recognize the service as unused overloading service that should be shut down. Here is the best way to maintain your service even if the app is closed: AlarmManager or Service

Community
  • 1
  • 1
3lomahmed
  • 849
  • 6
  • 10
  • Since you have it working fine before then all i can think of is that the issue from kitkat version it has bugs need to be fixed, I'm sorry i don't have other work arounds... – 3lomahmed Dec 16 '13 at 03:42
  • Here is a thread I found which addresses the issue. Seems like a bug in 4.4.1 and 4.4.2 https://groups.google.com/forum/#!topic/android-developers/H-DSQ4-tiac – geekoraul Dec 16 '13 at 08:14