Need code example on how to run an Android service forever in the background even when device sleeping, like Whatsapp?

I have tried various ways to achieve this, but my service eventually gets killed.

I want to use AlarmManager to trigger a class every one hour. Even if the device is sleeping, it should sent a flashing LED alert, vibration or sound. In any case, it should run forever.

I have noticed that Whatsapp is always running, even though I kill all the running apps and clear the memory, put the device to sleep, and still Whatsapp receive messages and alerts me. How are they doing it? I want to do the same with my app.


Solution 1:

NOTE: NOW THIS ANSWER IS ONLY VALID FOR ANDROID 7 AND BELOW. SINCE ANDROID 8 GOOGLE HAS CHANGED HOW BACKGROUND TASKS ARE HANDLED

Since I posted this question, I have implemented two different approaches to this solution into multiple apps.


APPROACH 1

This extract is from an app where I use push notifications, which need instant wake up calls for the device. Here what I do is

  1. use WAKE_LOCK permission and
  2. use a Wakelocker abstract class
  3. use it in an Activity as needed:

Manifest:

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

WakeLocker class:

public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;

public static void acquire(Context context) {
    if (wakeLock != null) wakeLock.release();

    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
            PowerManager.ACQUIRE_CAUSES_WAKEUP |
            PowerManager.ON_AFTER_RELEASE, "WakeLock");
    wakeLock.acquire();
}

public static void release() {
    if (wakeLock != null) wakeLock.release(); wakeLock = null;
}
}

Activity class example:

private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Waking up mobile if it is sleeping
        WakeLocker.acquire(getApplicationContext());
        // do something
        WakeLocker.release();
}

APPROACH 2

Best when you want to give Android control over wake up, and can live with periodically waking up your code. Simply use an AlarmManager to invoke a Service class at regular intervals. Here is some code from my LifeLog24 app:

MainActivity

Intent ll24 = new Intent(context, AlarmReceiverLifeLog.class);
    PendingIntent recurringLl24 = PendingIntent.getBroadcast(context, 0, ll24, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    alarms.setRepeating(AlarmManager.RTC_WAKEUP, first_log.getTime(), AlarmManager.INTERVAL_HOUR, recurringLl24); // Log repetition

Alarm Class

public class AlarmReceiverLifeLog extends BroadcastReceiver {

    private static final String TAG = "LL24";
    static Context context;

    @Override
    public void onReceive(Context context, Intent intent) {

        Log.v(TAG, "Alarm for LifeLog...");

        Intent ll24Service = new Intent(context, LifeLogService.class);
        context.startService(ll24Service);
    }
    }

and LifeLogService.class is where I do my stuff. Alarm wakes up every hour in this case and triggers the BroadcastReceiver which in return runs the service. There is more to it, to make sure service is not run twice and so on, but you get the point how it is done. And AlarmManager is actually the best way to do it since you don't worry about battery usage, etc. and Android takes care of waking up your Service at regular intervals.

Solution 2:

It is very simple.
steps:
1.create a Service class.
2.create a BroadcastReceiver class
3.call BroadReceiver in onDestroy method of service
4.In onReceive method of BroadReceiver class start service once again.

Here's the code

Manifest file:`

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <activity android:name=".LauncherActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service
        android:name=".utilities.NotificationService"
        android:enabled="true">

    </service>

    <receiver
        android:name=".utilities.RestartService"
        android:enabled="true"
        android:exported="true"
        android:label="RestartServiceWhenStopped"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
        <intent-filter>
            <action android:name="RestartService" />
        </intent-filter>
    </receiver>
</application>

`

Service class

public class NotificationService extends Service {
    public NotificationService() {
    }

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

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

   @Override
   public void onDestroy() {
       super.onDestroy();
       Intent restartService = new Intent("RestartService");
       sendBroadcast(restartService);
  }
}

BroadcastReceiver class

public class RestartService extends BroadcastReceiver {

     @Override
     public void onReceive(Context context, Intent intent) {

         context.startService(new Intent(context,NotificationService.class));
     }
 }

Solution 3:

Follow these easy steps to keep servce alive forever in android device. 1. Call a service by using alarm manager. 2. return START_STICKY in onStart method. 3. In on destroy call the alarm manager and restart service by using startService method. 4.(Optional)Repeat the point number 3 in onTaskRemoved method.

Solution 4:

Request partial WakeLock.

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

 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Tag");
mWakeLock.acquire();

onStartCommand retrun START_STICKY :

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