5

I am currently developing an email application which relies on a background service in order to be able to automatically fetch new emails. This works perfectly when the application is open (or in the running list of apps) but as soon as I close the app / remove it from the recent apps list, the service is also stopped. This can be confirmed by going into the 'Developer Settings' on the device and seeing that there are no processes or services running for my application.

I have read countless threads on StackOverflow but none of them seem to be doing the trick. Sometimes onTaskRemoved() is called and the service is restarted but then other times it isn't called at all or it is called, the logs show that the OS has scheduled a restart of the service but then the service gets forced closed by the OS whereas I always need to have this service running to retrieve new emails.

My current code can be seen below:

My Service:

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);

        Log.i(TAG, "onStartCommand()");

        ...

        Log.d(TAG, "SERVICE IS RUNNING");

        if (host != null) {
            Log.d(TAG, "STARTING PUSH SERVICE");

            Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG, "BR: " + ((BugReporting) getApplication()));
                    sharedRunnable = ((BugReporting) getApplication()).getSharedRunnable();

                    MailPush mailPush = new MailPush(getApplicationContext(), sharedRunnable);
                    Log.d(TAG, "sharedRunnable 1: " + sharedRunnable);
                    mailPush.checkInboxEmail(host, email, password);
                    //mailPush.checkSentEmail(host, email, password);
                }
            };
            handler.postDelayed(runnable, 5000);//0.5 seconds

        }

        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate()");
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.i(TAG, "onTaskRemoved()");

        PendingIntent service = PendingIntent.getService(
                getApplicationContext(),
                1001,
                new Intent(getApplicationContext(), MyService.class),
                PendingIntent.FLAG_ONE_SHOT);

        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy()");
        startService(new Intent(this, MyService.class));
    }

Reboot Receiver:

 public class AutoStart extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        context.startService(new Intent(context, MyService.class));
    }
}

Manifest:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

...

        <receiver
                android:name="uk.co.tundracorestudios.securemail.notification.AutoStart"
                android:enabled="true"
                android:exported="true"
                android:process=":remote">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                </intent-filter>
            </receiver>

            <service
                android:name="uk.co.tundracorestudios.securemail.notification.MyService"
                android:enabled="true"
                android:exported="true"
                android:label="@string/mail_service"
                android:stopWithTask="false"/>

I did attempt to run MyService as a different process but this then restricted me from getting the sharedRunnable that I have saved in the application class which can otherwise be access through:

 updateListRunnable = ((BugReporting) getApplication()).getSharedRunnable();

Therefore, I am asking, how can I ensure that my service continuously runs / works even when the application is closed or when the device is rebooted whilst still having access to the components located in getApplication()?

As when I attempted to run MyService as a separate process, the above updateListRunnable would always return null whereas when the application and service were running in the same process, it would return the correct runnable.

rafsanahmad007
  • 23,683
  • 6
  • 47
  • 62
Toby Clench
  • 403
  • 1
  • 5
  • 22

2 Answers2

4

I faced a similar issue a while back and used this in the onDestroy() method of my service:

public void onDestroy() {
    Intent restartService = new Intent(getApplicationContext(),this.getClass());
    PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(),1,restartService,PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    alarmManager.set(AlarmManager.ELAPSED_REALTIME,5000,pendingIntent);
    super.onDestroy();
}

When the service is being destoyed I set an alarm of 5 second, which will start my service aagain. This way your service will stop when user remove it from recent but it will start again.

nullvoid
  • 121
  • 8
  • Correct. `onTaskRemoved` is not part of a services lifecycle methods: https://developer.android.com/guide/components/services.html#Lifecycle `onTaskRemoved` description is here https://developer.android.com/reference/android/app/Service.html#onTaskRemoved(android.content.Intent) – Ryan Jan 16 '17 at 09:46
  • Thank you nullvoid! I have literally tried every solution provided on the internet, this has solved my problem where the force closed app is not getting notifications. Almost a 1 month struggle! Thank you for sharing your solution! – Lozy Jul 10 '17 at 19:37
  • Uhm..Services have `onDestroy()` method? – Azizjon Kholmatov Jul 19 '21 at 09:56
0

For me restarting the service using AlarmManager from onDestroy didn't work but starting the service from onTaskRemoved worked. When you kill the app while a service is running the onTaskRemoved function is triggered.

@Override
        public void onTaskRemoved(Intent rootIntent) {
            Log.d(TAG, "onTaskRemoved: removed");
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis() + 10000);
((AlarmManager) getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), RegisterReceiverService.class), 0));
            super.onTaskRemoved(rootIntent);
        }

So basically once you kill the app the service will be started after 10 seconds. Note: In case you want to use

AlarmManager.ELAPSED_REALTIME_WAKEUP

the minimum time after which you'll be able to restart the service will be 15 minutes.

Remember you also need to start the service on reboot using BroadcastReceiver.