geekoraul
geekoraul

Reputation: 2653

The process of the service is killed after the application is removed from the application tray

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

Upvotes: 34

Views: 46524

Answers (6)

Sam
Sam

Reputation: 42357

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.

Upvotes: 7

Ajith K P
Ajith K P

Reputation: 396

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

Upvotes: 1

lego king
lego king

Reputation: 638

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.

Upvotes: 1

Nick Jian
Nick Jian

Reputation: 455

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.

Upvotes: 7

geekoraul
geekoraul

Reputation: 2653

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.

Upvotes: 59

3lomahmed
3lomahmed

Reputation: 879

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

Upvotes: 0

Related Questions