Skip to content
AndroidAndroid

Android Background Work in 2026: Replacing IntentService and JobIntentServiceTrabajo en segundo plano en Android en 2026: sustituir IntentService y JobIntentService

ByPor David Cruz Anaya, Senior Mobile & Applied AI Engineer (Android, Kotlin Multiplatform, product AI)Ingeniero sénior de móvil e IA aplicada (Android, Kotlin Multiplatform, IA de producto)

Updated 11 July 2026Actualizado el 11 de julio de 20263 min read3 min de lectura
AndroidMobile DevelopmentKotlin
Android Background Work in 2026: Replacing IntentService and JobIntentService
Share:Compartir:

Android background work: replacing IntentService and JobIntentService

If you landed here from an old tutorial, do not reach for IntentService or JobIntentService in 2026. Both are deprecated. Deferrable background work goes to WorkManager. Work that has to run right now and keep going after the user leaves the app goes to a foreground service. Everything else belongs in a coroutine.

I first wrote this post in 2020 recommending JobIntentService, and that advice has aged out. I have rewritten it for how Android background work looks now, including a step-by-step migration off IntentService.

Why IntentService and JobIntentService are both deprecated

IntentService shipped back in API 3. It gave you a simple way to run work off the main thread: you handed it an Intent, it queued the work, ran onHandleIntent on a background thread, and stopped itself when the queue drained. For years it was the default choice, and it was convenient.

Then Android Oreo (API 26) introduced background execution limits to stop apps draining the battery with unbounded background services. A plain background service can no longer start freely while your app is in the background, which broke the IntentService model. Google marked IntentService deprecated in API 30 (Android 11). It is deprecated, not removed, so old code still compiles and runs. It will not reliably start from the background on modern devices.

JobIntentService behaved like IntentService on older devices and used JobScheduler on API 26 and above. It was a useful bridge, and it is exactly what I recommended in the original version of this post. But JobIntentService was itself deprecated in androidx.core 1.3.0. It was always meant to be a migration aid, not a destination.

So both classes are dead ends for new code, and WorkManager is where that work belongs now.

What should you use instead in 2026?

Pick based on what the work needs:

  • Deferrable, guaranteed work (uploads, syncs, sending logs, processing a download): use WorkManager. It selects the right scheduler under the hood, survives app restarts and reboots, honours constraints like “only on unmetered network” or “only while charging”, and works back to API 14.
  • Work that must run immediately and continue while the app is backgrounded (an active upload with a progress notification, audio, location): use a foreground service, or WorkManager expedited work with a foreground notification.
  • Simple async work tied to a screen (a network call for the current UI): you probably do not need a service at all. Use a Kotlin coroutine in your viewModelScope.

For the classic IntentService case, WorkManager is the direct replacement.

How to migrate IntentService to WorkManager

Here is the migration on a real example: an IntentService that uploads a file.

  1. Add the WorkManager dependency in your module build.gradle.kts. Check for the latest stable version when you add it.
implementation("androidx.work:work-runtime-ktx:2.10.0")
  1. Turn the IntentService into a CoroutineWorker. The old onHandleIntent body becomes doWork. Because doWork is a suspend function, you get structured concurrency for free and never touch a thread by hand.
class UploadWorker(
    context: Context,
    params: WorkerParameters,
) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        val fileUri = inputData.getString(KEY_FILE_URI) ?: return Result.failure()
        return try {
            uploadFile(fileUri)
            Result.success()
        } catch (e: IOException) {
            Result.retry()
        }
    }

    companion object {
        const val KEY_FILE_URI = "file_uri"
    }
}
  1. Replace context.startService(intent) with an enqueued WorkRequest. Whatever you used to pack into the Intent extras now goes into inputData.
val request = OneTimeWorkRequestBuilder<UploadWorker>()
    .setInputData(workDataOf(UploadWorker.KEY_FILE_URI to fileUri))
    .build()

WorkManager.getInstance(context).enqueue(request)
  1. Delete the <service> entry from AndroidManifest.xml. WorkManager registers its own component through the app-startup provider, so the old service tag and the BIND_JOB_SERVICE permission both go away.

That is the whole migration.

If you need the work to start as soon as possible rather than when the system feels like it, mark it expedited. By default WorkManager optimises for battery, so work can be delayed.

val request = OneTimeWorkRequestBuilder<UploadWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

Happy coding.

David Cruz davthecoder.com

Trabajo en segundo plano en Android: sustituir IntentService y JobIntentService

Si has llegado aquí desde un tutorial antiguo, no eches mano de IntentService ni de JobIntentService en 2026. Los dos están obsoletos. El trabajo en segundo plano que se puede aplazar va a WorkManager. El trabajo que tiene que ejecutarse ahora mismo y seguir después de que el usuario salga de la app va a un servicio en primer plano. Todo lo demás va en una corrutina.

Escribí este artículo por primera vez en 2020 recomendando JobIntentService, y ese consejo ha quedado desfasado. Lo he reescrito según cómo es el trabajo en segundo plano en Android ahora, incluida una migración paso a paso para dejar atrás IntentService.

Por qué IntentService y JobIntentService están obsoletos

IntentService salió en la API 3. Te daba una forma sencilla de ejecutar trabajo fuera del hilo principal: le pasabas un Intent, encolaba el trabajo, ejecutaba onHandleIntent en un hilo en segundo plano y se paraba solo cuando la cola se vaciaba. Durante años fue la opción por defecto, y era cómodo.

Luego Android Oreo (API 26) introdujo los límites de ejecución en segundo plano para que las apps dejaran de agotar la batería con servicios en segundo plano sin límite. Un servicio en segundo plano normal ya no puede arrancar libremente mientras tu app está en segundo plano, y eso rompió el modelo de IntentService. Google marcó IntentService como obsoleto en la API 30 (Android 11). Está obsoleto, no eliminado, así que el código viejo sigue compilando y ejecutándose. No arranca de forma fiable desde segundo plano en dispositivos modernos.

JobIntentService se comportaba como IntentService en dispositivos antiguos y usaba JobScheduler en la API 26 y superiores. Fue un puente útil, y es exactamente lo que recomendé en la versión original de este artículo. Pero el propio JobIntentService quedó obsoleto en androidx.core 1.3.0. Siempre estuvo pensado como ayuda para la migración, no como destino.

Así que las dos clases son un callejón sin salida para código nuevo, y ese trabajo ahora corresponde a WorkManager.

¿Qué deberías usar en su lugar en 2026?

Elige según lo que el trabajo necesite:

  • Trabajo aplazable y garantizado (subidas, sincronizaciones, envío de logs, procesar una descarga): usa WorkManager. Elige el planificador adecuado por debajo, sobrevive a los reinicios de la app y del dispositivo, respeta restricciones como «solo en red no medida» o «solo mientras carga», y funciona desde la API 14.
  • Trabajo que debe ejecutarse de inmediato y continuar con la app en segundo plano (una subida activa con notificación de progreso, audio, ubicación): usa un servicio en primer plano, o trabajo expedited de WorkManager con una notificación en primer plano.
  • Trabajo asíncrono sencillo ligado a una pantalla (una llamada de red para la UI actual): seguramente no necesitas un servicio en absoluto. Usa una corrutina de Kotlin en tu viewModelScope.

Para el caso clásico de IntentService, WorkManager es el reemplazo directo.

Cómo migrar de IntentService a WorkManager

Aquí va la migración con un ejemplo real: un IntentService que sube un fichero.

  1. Añade la dependencia de WorkManager en el build.gradle.kts de tu módulo. Comprueba la última versión estable cuando la añadas.
implementation("androidx.work:work-runtime-ktx:2.10.0")
  1. Convierte el IntentService en un CoroutineWorker. El cuerpo antiguo de onHandleIntent pasa a ser doWork. Como doWork es una función suspend, la concurrencia estructurada te sale gratis y no tocas un hilo a mano.
class UploadWorker(
    context: Context,
    params: WorkerParameters,
) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        val fileUri = inputData.getString(KEY_FILE_URI) ?: return Result.failure()
        return try {
            uploadFile(fileUri)
            Result.success()
        } catch (e: IOException) {
            Result.retry()
        }
    }

    companion object {
        const val KEY_FILE_URI = "file_uri"
    }
}
  1. Sustituye context.startService(intent) por un WorkRequest encolado. Lo que antes metías en los extras del Intent ahora va en inputData.
val request = OneTimeWorkRequestBuilder<UploadWorker>()
    .setInputData(workDataOf(UploadWorker.KEY_FILE_URI to fileUri))
    .build()

WorkManager.getInstance(context).enqueue(request)
  1. Borra la entrada <service> de AndroidManifest.xml. WorkManager registra su propio componente a través del provider de App Startup, así que desaparecen tanto la etiqueta antigua del servicio como el permiso BIND_JOB_SERVICE.

Esa es toda la migración.

Si necesitas que el trabajo arranque lo antes posible, y no cuando al sistema le apetezca, márcalo como expedited. Por defecto WorkManager optimiza la batería, así que el trabajo puede retrasarse.

val request = OneTimeWorkRequestBuilder<UploadWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

¡Feliz programación!

David Cruz davthecoder.com

Share:Compartir:

CommentsComentarios

Loading comments…Cargando comentarios…