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 scheduleWorkManagerfor 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 pendingPendingIntent) 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 viaAlarmManagerorWorkManager. - Use
WorkManagerfor 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 theFOREGROUND_SERVICEpermission 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_STICKYis not enough. - May not be aware of background execution limits introduced in Android 8+ and tightened in Android 12+.