Skip to main content

Choosing the right background API

“Run this in the background” is incomplete. First ask how long, when, must it survive process death, and must the user know it is running?

RequirementUsually chooseWhy
Work needed only while this screen/ViewModel existscoroutine in a lifecycle scopeCancellation follows the owner
Deferrable upload that must eventually finishWorkManagerPersists and reschedules durable work
User-visible, ongoing activity nowforeground serviceExplicit notification and stronger execution eligibility
Exact user-facing alarm at 07:00AlarmManager exact alarm, if permittedTiming—not eventual execution—is the contract
Continuous same-process client/server interactionbound serviceComponents bind to a service interface

Scenario 1: save a form​

fun saveDraft() = viewModelScope.launch {
repository.saveDraft(editorState.value)
}

This coroutine is correct if cancellation when the ViewModel is cleared is acceptable. A coroutine is not durable scheduling. The OS may kill the process after the app leaves the screen.

Scenario 2: upload a receipt even after the app closes​

val request = OneTimeWorkRequestBuilder<ReceiptUploadWorker>()
.setInputData(workDataOf("receiptId" to receiptId))
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()

WorkManager.getInstance(context).enqueueUniqueWork(
"receipt-upload-$receiptId",
ExistingWorkPolicy.KEEP,
request,
)

Pass an ID, not a bitmap or large JSON document. The worker reloads current data from durable storage.

Scenario 3: navigation recording​

A visible trip recording initiated by the user may require a location foreground service. WorkManager is wrong for an unbounded, continuously active session; an ordinary coroutine is too easy for the system to terminate once the app is backgrounded.

Common mistakes​

  • ❌ Start a service for every asynchronous operation.
  • ✅ Use a coroutine for in-process work and WorkManager for durable, deferrable work.
  • ❌ Use an exact alarm for periodic synchronization.
  • ✅ Let WorkManager batch deferrable sync for battery efficiency.
  • ❌ Assume WorkManager starts at an exact clock time.
  • ✅ Treat it as “not before constraints permit, eventually,” not a punctual scheduler.
A foreground service is not a loophole

It must perform a user-beneficial, user-visible task, declare the correct service type, show a notification, and comply with background-start restrictions.

Sources​

Interview check​

Question: Why not put every operation in viewModelScope?
Answer: Its lifetime is the ViewModel and therefore the current process. It does not guarantee execution after process death or reboot.