How to Restart an Android Service After Swipe‑Away Using onTaskRemoved

Summary

When a user swipes an app away from the Recent Tasks list Android treats it as a request to stop the app’s process.
A normal foreground service or START_STICKY cannot survive this request unless you explicitly tell the system you own the task and need to keep a component alive. The only supported way is to use a Service with onTaskRemoved() that restarts itself (or a WorkManager job for bounded work).

Key takeaways

  • Android intentionally kills the process after a swipe; you cannot prevent that completely.
  • The recommended pattern is self‑restart in onTaskRemoved() or schedule WorkManager for periodic work.
  • Starting with Android 12, background execution limits make it harder to keep a service alive for long periods.

Root Cause

  • Swipe‑away = task removal – the system calls onTaskRemoved() on every component belonging to that task.
  • After onTaskRemoved() returns, Android clears the task and kills the process unless something (e.g., a pending PendingIntent) tells it to stay alive.
  • Foreground services are still bound to the task’s lifecycle; they are stopped when the task is removed unless they re‑schedule themselves.

Why This Happens in Real Systems

  • Prevents resource abuse (battery, memory, network) by rogue apps that hide forever.
  • Guarantees a consistent user experience: swiping away means “I’m done with this app”.
  • Enforces privacy/security – a hidden process could continue collecting data without user knowledge.

Real-World Impact

  • Battery drain if apps ignore the swipe and keep running.
  • App store policy violations → possible rejection from Google Play.
  • Users lose trust when an app “won’t go away”.

Example or Code (if necessary and relevant)

class KeepAliveService : Service() {

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // promote to foreground so the system sees it as important
        startForeground(1, createNotification())
        return START_STICKY
    }

    override fun onTaskRemoved(rootIntent: Intent?) {
        // restart the service after a short delay
        val restartIntent = Intent(applicationContext, KeepAliveService::class.java)
        restartIntent.setPackage(packageName)

        val pending = PendingIntent.getService(
            this,
            1,
            restartIntent,
            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
        )

        val alarm = getSystemService(ALARM_SERVICE) as AlarmManager
        alarm.setExact(
            AlarmManager.ELAPSED_REALTIME,
            SystemClock.elapsedRealtime() + 1000,
            pending
        )
        super.onTaskRemoved(rootIntent)
    }

    override fun onBind(intent: Intent?) = null
}

How Senior Engineers Fix It

  • Declare a foreground service with a persistent notification.
  • Implement onTaskRemoved() to schedule a restart via AlarmManager or WorkManager.
  • Use WorkManager for periodic or one‑off background work that must survive app kills.
  • Target API levels correctly: add android:foregroundServiceType="location|mediaPlayback|dataSync" if needed, and request the FOREGROUND_SERVICE permission on Android 12+.
  • Test on real devices with battery‑optimizations disabled, because OEMs may add their own restrictions.

Why Juniors Miss It

  • Assume a foreground service is immune to task removal.
  • Forget that onTaskRemoved() is the hook where Android tells you the task is being cleared.
  • Overlook the need to schedule a restart (AlarmManager/WorkManager) – simply returning START_STICKY is not enough.
  • May not be aware of background execution limits introduced in Android 8+ and tightened in Android 12+.

Leave a Comment