Este codelab es parte del curso Conceptos básicos de Kotlin para Android. Aprovecharás al máximo este curso si trabajas con los codelabs de forma secuencial. Todos los codelabs del curso se enumeran en la página de destino de los codelabs de Android Kotlin Fundamentals.
Introducción
La mayoría de las apps del mundo real necesitan realizar tareas en segundo plano de larga duración. Por ejemplo, una app podría subir archivos a un servidor, sincronizar datos desde un servidor y guardarlos en una base de datos de Room
, enviar registros a un servidor o ejecutar operaciones costosas en los datos. Estas operaciones deben realizarse en segundo plano, fuera del subproceso de IU (subproceso principal). Las tareas en segundo plano consumen los recursos limitados de un dispositivo, como la RAM y la batería. Esto puede causar una experiencia del usuario deficiente si no se maneja de forma adecuada.
En este codelab, aprenderás a usar WorkManager
para programar una tarea en segundo plano de manera optimizada y eficiente. Si deseas obtener más información sobre otras soluciones disponibles para el procesamiento en segundo plano en Android, consulta la Guía para el procesamiento en segundo plano.
Conocimientos que ya deberías tener
- Cómo usar los componentes de la arquitectura de Android
ViewModel
,LiveData
yRoom
- Cómo realizar transformaciones en una clase
LiveData
- Cómo compilar y lanzar una corrutina
- Cómo usar adaptadores de vinculación en la vinculación de datos
- Cómo cargar datos almacenados en caché con un patrón de repositorio
Qué aprenderás
- Cómo crear un
Worker
, que representa una unidad de trabajo - Cómo crear un
WorkRequest
para solicitar que se realice un trabajo - Cómo agregar restricciones al
WorkRequest
para definir cómo y cuándo se debe ejecutar un worker - Cómo usar
WorkManager
para programar tareas en segundo plano
Actividades
- Crea un worker para ejecutar una tarea en segundo plano que recupere previamente la playlist de videos de DevBytes de la red.
- Programa el trabajador para que se ejecute de forma periódica.
- Agrega restricciones al
WorkRequest
. - Programa un
WorkRequest
periódico que se ejecute una vez al día.
En este codelab, trabajarás en la app de DevBytes que desarrollaste en un codelab anterior. (Si no tienes esta app, puedes descargar el código de partida para esta lección).
La app de DevBytes muestra una lista de videos de DevBytes, que son instructivos breves creados por el equipo de relaciones con desarrolladores de Android de Google. En los videos, se presentan las funciones para desarrolladores y las prácticas recomendadas para el desarrollo de Android.
Mejoraste la experiencia del usuario en la app realizando una recuperación previa de los videos una vez al día. Esto garantiza que el usuario obtenga contenido nuevo en cuanto abra la app.
En esta tarea, descargarás y revisarás el código de partida.
Paso 1: Descarga y ejecuta la app de inicio
Puedes seguir trabajando en la app de DevBytes que compilaste en el codelab anterior (si la tienes). También puedes descargar la app de inicio.
En esta tarea, descargarás y ejecutarás la app de inicio, y examinarás el código de inicio.
- Si aún no tienes la app de DevBytes, descarga el código de partida de DevBytes para este codelab desde el proyecto DevBytesRepository de GitHub.
- Descomprime el código y abre el proyecto en Android Studio.
- Conecta tu dispositivo de prueba o emulador a Internet si aún no lo está. Compila y ejecuta la app. La app recupera la lista de videos de DevByte de la red y los muestra.
- En la app, presiona cualquier video para abrirlo en la app de YouTube.
Paso 2: Explora el código
La app de inicio incluye mucho código que se presentó en el codelab anterior. El código de partida de este codelab tiene módulos de redes, interfaz de usuario, caché sin conexión y repositorio. Puedes enfocarte en programar la tarea en segundo plano con WorkManager
.
- En Android Studio, expande todos los paquetes.
- Explora el paquete
database
. El paquete contiene las entidades de la base de datos y la base de datos local, que se implementa conRoom
. - Explora el paquete
repository
. El paquete contiene la claseVideosRepository
que abstrae la capa de datos del resto de la app. - Explora el resto del código de partida por tu cuenta y con la ayuda del codelab anterior.
WorkManager
es uno de los componentes de la arquitectura de Android y parte de Android Jetpack. WorkManager
es para el trabajo en segundo plano que se puede diferir y requiere una ejecución garantizada:
- Diferible significa que el trabajo no debe ejecutarse de inmediato. Por ejemplo, enviar datos analíticos al servidor o sincronizar la base de datos en segundo plano son tareas que se pueden aplazar.
- La ejecución garantizada significa que la tarea se ejecutará incluso si se cierra la app o se reinicia el dispositivo.
Mientras WorkManager
ejecuta el trabajo en segundo plano, se encarga de los problemas de compatibilidad y las prácticas recomendadas para la batería y el estado del sistema. WorkManager
ofrece compatibilidad hasta el nivel de API 14. WorkManager
elige una forma adecuada de programar una tarea en segundo plano, según el nivel de API del dispositivo. Puede usar JobScheduler
(en el nivel de API 23 y versiones posteriores) o una combinación de AlarmManager
y BroadcastReceiver
.
WorkManager
también te permite establecer criterios sobre cuándo se ejecuta la tarea en segundo plano. Por ejemplo, es posible que quieras que la tarea se ejecute solo cuando el estado de la batería, el estado de la red o el estado de carga cumplan con ciertos criterios. Aprenderás a establecer restricciones más adelante en este codelab.
En este codelab, programarás una tarea para recuperar previamente la lista de reproducción de videos de DevBytes de la red una vez al día. Para programar esta tarea, usa la biblioteca WorkManager
.
- Abre el archivo
build.gradle (Module:app)
y agrega la dependenciaWorkManager
al proyecto.
Si usas la versión más reciente de la biblioteca, la app de solución debería compilarse según lo esperado. Si no es así, intenta resolver el problema o vuelve a la versión de la biblioteca que se muestra a continuación.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
- Sincroniza tu proyecto y asegúrate de que no haya errores de compilación.
Antes de agregar código al proyecto, familiarízate con las siguientes clases de la biblioteca WorkManager
:
Worker
En esta clase, defines el trabajo real (la tarea) que se ejecutará en segundo plano. Extiendes esta clase y anulas el métododoWork()
. El métododoWork()
es donde colocas el código que se ejecutará en segundo plano, como la sincronización de datos con el servidor o el procesamiento de imágenes. En esta tarea, implementarásWorker
.WorkRequest
Esta clase representa una solicitud para ejecutar el trabajador en segundo plano. UsaWorkRequest
para configurar cómo y cuándo ejecutar la tarea del trabajador, con la ayuda deConstraints
, como el dispositivo enchufado o la conexión Wi-Fi. ImplementarásWorkRequest
en una tarea posterior.WorkManager
Esta clase programa y ejecuta tuWorkRequest
.WorkManager
programa solicitudes de trabajo de manera que se distribuya la carga sobre los recursos del sistema, respetando las restricciones que hayas especificado. ImplementarásWorkManager
en una tarea posterior.
Paso 1: Crea un trabajador
En esta tarea, agregarás un Worker
para recuperar previamente la playlist de videos de DevBytes en segundo plano.
- Dentro del paquete
devbyteviewer
, crea un paquete nuevo llamadowork
. - En el paquete
work
, crea una nueva clase de Kotlin llamadaRefreshDataWorker
. - Extiende la clase
RefreshDataWorker
desdeCoroutineWorker
. Pasacontext
yWorkerParameters
como parámetros del constructor.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
}
- Para resolver el error de clase abstracta, anula el método
doWork()
dentro de la claseRefreshDataWorker
.
override suspend fun doWork(): Result {
return Result.success()
}
Una función de suspensión es una función que se puede pausar y reanudar más tarde. Una función de suspensión puede ejecutar una operación de larga duración y esperar a que se complete sin bloquear el subproceso principal.
Paso 2: Implementa doWork()
Se llama al método doWork()
dentro de la clase Worker
en un subproceso en segundo plano. El método realiza el trabajo de forma síncrona y debe devolver un objeto ListenableWorker.Result
. El sistema Android le otorga a un Worker
un máximo de 10 minutos para finalizar su ejecución y devolver un objeto ListenableWorker.Result
. Una vez que vence este tiempo, el sistema detiene de forma forzosa el Worker
.
Para crear un objeto ListenableWorker.Result
, llama a uno de los siguientes métodos estáticos para indicar el estado de finalización del trabajo en segundo plano:
Result.success()
: El trabajo se completó correctamente.Result.failure()
: El trabajo se completó con una falla permanente.Result.retry()
: El trabajo encontró un error transitorio y se debe reintentar.
En esta tarea, implementarás el método doWork()
para recuperar la playlist de videos de DevBytes de la red. Puedes reutilizar los métodos existentes en la clase VideosRepository
para recuperar los datos de la red.
- En la clase
RefreshDataWorker
, dentro dedoWork()
, crea una instancia de un objetoVideosDatabase
y un objetoVideosRepository
.
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
return Result.success()
}
- En la clase
RefreshDataWorker
, dentro dedoWork()
, sobre la sentenciareturn
, llama al métodorefreshVideos()
dentro de un bloquetry
. Agrega un registro para hacer un seguimiento de cuándo se ejecuta el trabajador.
try {
repository.refreshVideos( )
Timber.d("Work request for sync is run")
} catch (e: HttpException) {
return Result.retry()
}
Para resolver el error "Unresolved reference", importa retrofit2.HttpException
.
- Aquí se encuentra la clase
RefreshDataWorker
completa para tu referencia:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
try {
repository.refreshVideos()
} catch (e: HttpException) {
return Result.retry()
}
return Result.success()
}
}
Un Worker
define una unidad de trabajo, y el WorkRequest
define cómo y cuándo se debe ejecutar el trabajo. Existen dos implementaciones concretas de la clase WorkRequest
:
- La clase
OneTimeWorkRequest
sirve para tareas únicas. (Una tarea única ocurre solo una vez). - La clase
PeriodicWorkRequest
sirve para trabajo periódico y para tareas que se repiten por intervalos.
Las tareas pueden ser únicas o periódicas, así que elige la clase según corresponda. Para obtener más información sobre la programación de trabajos recurrentes, consulta la documentación relacionada.
En esta tarea, definirás y programarás un WorkRequest
para ejecutar el worker que creaste en la tarea anterior.
Paso 1: Configura el trabajo recurrente
En una app para Android, la clase Application
es la clase base que contiene todos los demás componentes, como actividades y servicios. Cuando se crea el proceso para tu aplicación o paquete, se crea una instancia de la clase Application
(o cualquier subclase de Application
) antes que cualquier otra clase.
En esta app de ejemplo, la clase DevByteApplication
es una subclase de la clase Application
. La clase DevByteApplication
es un buen lugar para programar el WorkManager
.
- En la clase
DevByteApplication
, crea un método llamadosetupRecurringWork()
para configurar el trabajo recurrente en segundo plano.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
- Dentro del método
setupRecurringWork()
, crea e inicializa una solicitud de trabajo periódica para que se ejecute una vez al día con el métodoPeriodicWorkRequestBuilder()
. Pasa la claseRefreshDataWorker
que creaste en la tarea anterior. Pasa un intervalo de repetición de1
con una unidad de tiempo deTimeUnit.
DAYS
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.build()
Para resolver el error, importa java.util.concurrent.TimeUnit
.
Paso 2: Programa una WorkRequest con WorkManager
Después de definir tu WorkRequest
, puedes programarla con WorkManager
usando el método enqueueUniquePeriodicWork()
. Este método te permite agregar un PeriodicWorkRequest
con un nombre único a la fila, en la que solo puede haber un PeriodicWorkRequest
con un nombre determinado activo a la vez.
Por ejemplo, es posible que solo quieras que una operación de sincronización esté activa. Si hay una operación de sincronización pendiente, puedes dejar que se ejecute o reemplazarla por tu nuevo trabajo con un ExistingPeriodicWorkPolicy.
Para obtener más información sobre las formas de programar un WorkRequest
, consulta la documentación de WorkManager
.
- En la clase
RefreshDataWorker
, al comienzo de la clase, agrega un objeto complementario. Define un nombre de trabajador para identificarlo de forma única.
companion object {
const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
- En la clase
DevByteApplication
, al final del métodosetupRecurringWork()
, programa el trabajo con el métodoenqueueUniquePeriodicWork()
. Pasa el enumKEEP
para ExistingPeriodicWorkPolicy. PasarepeatingRequest
como el parámetroPeriodicWorkRequest
.
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
Si existe trabajo pendiente (incompleto) con el mismo nombre, el parámetro ExistingPeriodicWorkPolicy.
KEEP
hace que WorkManager
conserve el trabajo periódico anterior y descarte la nueva solicitud de trabajo.
- Al comienzo de la clase
DevByteApplication
, crea un objetoCoroutineScope
. PasaDispatchers.Default
como parámetro del constructor.
private val applicationScope = CoroutineScope(Dispatchers.Default)
- En la clase
DevByteApplication
, agrega un método nuevo llamadodelayedInit()
para iniciar una corrutina.
private fun delayedInit() {
applicationScope.launch {
}
}
- Dentro del método
delayedInit()
, llama asetupRecurringWork()
. - Mueve la inicialización de Timber del método
onCreate()
al métododelayedInit()
.
private fun delayedInit() {
applicationScope.launch {
Timber.plant(Timber.DebugTree())
setupRecurringWork()
}
}
- En la clase
DevByteApplication
, al final del métodoonCreate()
, agrega una llamada al métododelayedInit()
.
override fun onCreate() {
super.onCreate()
delayedInit()
}
- Abre el panel Logcat en la parte inferior de la ventana de Android Studio. Filtrar por
RefreshDataWorker
- Ejecuta la app.
WorkManager
programa tu trabajo recurrente de inmediato.
En el panel Logcat, observa las instrucciones de registro que muestran que la solicitud de trabajo se programó y, luego, se ejecutó correctamente.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
El registro WM-WorkerWrapper
se muestra desde la biblioteca WorkManager
, por lo que no puedes cambiar este mensaje de registro.
Paso 3: (Opcional) Programa el WorkRequest para un intervalo mínimo
En este paso, disminuyes el intervalo de tiempo de 1 día a 15 minutos. Esto te permitirá ver los registros de una solicitud de trabajo periódica en acción.
- En la clase
DevByteApplication
, dentro del métodosetupRecurringWork()
, comenta la definición actual derepeatingRequest
. Agrega una nueva solicitud de trabajo con un intervalo de repetición periódico de15
minutos.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
// .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.build()
- Abre el panel Logcat en Android Studio y filtra por
RefreshDataWorker
. Para borrar los registros anteriores, haz clic en el ícono Borrar logcat.
- Ejecuta la app y
WorkManager
programará tu trabajo recurrente de inmediato. En el panel Logcat, observa los registros: la solicitud de trabajo se ejecuta una vez cada 15 minutos. Espera 15 minutos para ver otro conjunto de registros de solicitudes de trabajo. Puedes dejar la app en ejecución o cerrarla. El administrador de trabajo debería seguir ejecutándose.
Ten en cuenta que, a veces, el intervalo es inferior a 15 minutos y, otras veces, superior. (El momento exacto está sujeto a las optimizaciones de batería del SO).
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
¡Felicitaciones! Creaste un trabajador y programaste la solicitud de trabajo con WorkManager
. Pero hay un problema: no especificaste ninguna restricción. WorkManager
programará el trabajo una vez al día, incluso si el dispositivo tiene poca batería, está en suspensión o no tiene conexión de red. Esto afectará la batería y el rendimiento del dispositivo, y podría generar una mala experiencia del usuario.
En la próxima tarea, agregarás restricciones para abordar este problema.
En la tarea anterior, usaste WorkManager
para programar una solicitud de trabajo. En esta tarea, agregarás criterios para determinar cuándo ejecutar el trabajo.
Cuando defines el WorkRequest
, puedes especificar restricciones para el momento en que se debe ejecutar el Worker
. Por ejemplo, puedes especificar que el trabajo solo se ejecute cuando el dispositivo esté inactivo o solo cuando esté enchufado y conectado a Wi-Fi. También puedes especificar una política de reintentos para volver a intentar el trabajo. Las restricciones admitidas son los métodos de configuración en Constraints.Builder
. Para obtener más información, consulta Cómo definir tus solicitudes de trabajo.
Paso 1: Agrega un objeto Constraints y establece una restricción
En este paso, crearás un objeto Constraints
y establecerás una restricción en el objeto, una restricción de tipo de red. (Es más fácil notar los registros con una sola restricción. En un paso posterior, agregarás otras restricciones.
- En la clase
DevByteApplication
, al comienzo desetupRecurringWork()
, define unval
del tipoConstraints
. Usa el métodoConstraints.Builder()
.
val constraints = Constraints.Builder()
Para resolver el error, importa androidx.work.Constraints
.
- Usa el método
setRequiredNetworkType()
para agregar una restricción de tipo de red al objetoconstraints
. Usa la enumeraciónUNMETERED
para que la solicitud de trabajo solo se ejecute cuando el dispositivo esté en una red no medida.
.setRequiredNetworkType(NetworkType.UNMETERED)
- Usa el método
build()
para generar las restricciones del compilador.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
Ahora debes establecer el objeto Constraints
recién creado en la solicitud de trabajo.
- En la clase
DevByteApplication
, dentro del métodosetupRecurringWork()
, establece el objetoConstraints
en la solicitud de trabajo periódica,repeatingRequest
. Para establecer las restricciones, agrega el métodosetConstraints()
sobre la llamada al métodobuild()
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.setConstraints(constraints)
.build()
Paso 2: Ejecuta la app y observa los registros
En este paso, ejecutarás la app y observarás que la solicitud de trabajo restringida se ejecuta en segundo plano en intervalos.
- Desinstala la app del dispositivo o emulador para cancelar las tareas programadas con anterioridad.
- Abre el panel Logcat en Android Studio. En el panel Logcat, borra los registros anteriores haciendo clic en el ícono Clear logcat
a la izquierda. Filtrar por
work
- Desactiva la conexión Wi-Fi en el dispositivo o el emulador para que puedas ver cómo funcionan las restricciones. El código actual solo establece una restricción, lo que indica que la solicitud solo debe ejecutarse en una red sin medición. Como el Wi-Fi está desactivado, el dispositivo no está conectado a la red, ya sea de uso medido o no medido. Por lo tanto, no se cumplirá esta restricción.
- Ejecuta la app y observa el panel de Logcat.
WorkManager
programa la tarea en segundo plano de inmediato. Como no se cumple la restricción de red, no se ejecuta la tarea.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- Activa la conexión Wi-Fi en el dispositivo o el emulador y observa el panel Logcat. Ahora, la tarea en segundo plano programada se ejecuta aproximadamente cada 15 minutos, siempre que se cumpla la restricción de red.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Paso 3: Agrega más restricciones
En este paso, agregarás las siguientes restricciones a PeriodicWorkRequest
:
- La batería no está baja.
- Carga del dispositivo
- Inactividad del dispositivo: Solo disponible en el nivel de API 23 (Android M) y versiones posteriores.
Implementa lo siguiente en la clase DevByteApplication
.
- En la clase
DevByteApplication
, dentro del métodosetupRecurringWork()
, indica que la solicitud de trabajo solo debe ejecutarse si la batería no está baja. Agrega la restricción antes de la llamada al métodobuild()
y usa el métodosetRequiresBatteryNotLow()
.
.setRequiresBatteryNotLow(true)
- Actualiza la solicitud de trabajo para que se ejecute solo cuando el dispositivo se esté cargando. Agrega la restricción antes de la llamada al método
build()
y usa el métodosetRequiresCharging()
.
.setRequiresCharging(true)
- Actualiza la solicitud de trabajo para que se ejecute solo cuando el dispositivo esté inactivo. Agrega la restricción antes de la llamada al método
build()
y usa el métodosetRequiresDeviceIdle()
. Esta restricción ejecuta la solicitud de trabajo solo cuando el usuario no está usando el dispositivo de forma activa. Esta función solo está disponible en Android 6.0 (Marshmallow) y versiones posteriores, por lo que debes agregar una condición para la versión del SDKM
y versiones posteriores.
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
Esta es la definición completa del objeto constraints
.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
- Dentro del método
setupRecurringWork()
, vuelve a cambiar el intervalo de solicitudes a una vez al día.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Aquí se muestra la implementación completa del método setupRecurringWork()
, con un registro para que puedas hacer un seguimiento de cuándo se programa la solicitud de trabajo periódica.
private fun setupRecurringWork() {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Timber.d("Periodic Work request for sync is scheduled")
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
}
- Para quitar la solicitud de trabajo programada anteriormente, desinstala la app de DevBytes de tu dispositivo o emulador.
- Ejecuta la app y
WorkManager
programará de inmediato la solicitud de trabajo. La solicitud de trabajo se ejecuta una vez al día, cuando se cumplen todas las restricciones. - Esta solicitud de trabajo se ejecutará en segundo plano mientras la app esté instalada, incluso si no se está ejecutando. Por ese motivo, debes desinstalar la app del teléfono.
¡Bien hecho! Implementaste y programaste una solicitud de trabajo que no consume mucha batería para la recuperación previa diaria de videos en la app de DevBytes. WorkManager
programará y ejecutará el trabajo, lo que optimizará los recursos del sistema. Tus usuarios y sus baterías estarán muy contentos.
Proyecto de Android Studio: DevBytesWorkManager
- La API de
WorkManager
facilita la programación de tareas asíncronas diferibles que se deben ejecutar de manera confiable. - La mayoría de las apps del mundo real necesitan realizar tareas en segundo plano de larga duración. Para programar una tarea en segundo plano de manera optimizada y eficiente, usa
WorkManager
. - Las clases principales de la biblioteca
WorkManager
sonWorker
,WorkRequest
yWorkManager
. - La clase
Worker
representa una unidad de trabajo. Para implementar la tarea en segundo plano, extiende la claseWorker
y anula el métododoWork()
. - La clase
WorkRequest
representa una solicitud para realizar una unidad de trabajo.WorkRequest
es la clase base para especificar parámetros para el trabajo que programas enWorkManager
. - Hay dos implementaciones concretas de la clase
WorkRequest
:OneTimeWorkRequest
para tareas únicas yPeriodicWorkRequest
para solicitudes de trabajo periódicas. - Cuando definas el
WorkRequest
, puedes especificarConstraints
para indicar cuándo se debe ejecutar elWorker
. Las restricciones incluyen aspectos como si el dispositivo está enchufado, si está inactivo o si está conectado a Wi-Fi. - Para agregar restricciones al
WorkRequest
, usa los métodos de configuración que se indican en la documentación deConstraints.Builder
. Por ejemplo, para indicar queWorkRequest
no debe ejecutarse si la batería del dispositivo está baja, usa el método setsetRequiresBatteryNotLow()
. - Después de definir el
WorkRequest
, transfiere la tarea al sistema Android. Para ello, programa la tarea con uno de los métodosenqueue
deWorkManager
. - La hora exacta en la que se ejecuta el
Worker
depende de las limitaciones que se usen en elWorkRequest
y de las optimizaciones del sistema.WorkManager
está diseñado para tener el mejor comportamiento posible, dadas estas restricciones.
Curso de Udacity:
Documentación para desarrolladores de Android:
- Cómo definir tus solicitudes de trabajo
WorkManager
- Cómo comenzar a usar WorkManager
- Trabajo recurrente
- Guía para el procesamiento en segundo plano
Otro:
En esta sección, se enumeran las posibles actividades para el hogar para los alumnos que trabajan en este codelab como parte de un curso dirigido por un instructor. Depende del instructor hacer lo siguiente:
- Si es necesario, asigna una tarea.
- Comunicarles a los alumnos cómo enviar las actividades para el hogar.
- Califica las actividades para el hogar.
Los instructores pueden usar estas sugerencias en la medida que quieran y deben asignar cualquier otra actividad para el hogar que consideren apropiada.
Si estás trabajando en este codelab por tu cuenta, usa estas actividades para el hogar para probar tus conocimientos.
Pregunta 1
¿Cuáles son las implicaciones concretas de la clase WorkRequest
?
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest
y PeriodicWorkRequest
▢ OneTimeWorkRequest
y RecurringWorkRequest
▢ OneTimeOffWorkRequest
y RecurringWorkRequest
Pregunta 2
¿Cuál de las siguientes clases usa WorkManager
para programar la tarea en segundo plano en el nivel de API 23 y versiones posteriores?
▢ Solo JobScheduler
▢ BroadcastReceiver
y AlarmManager
▢ AlarmManager
y JobScheduler
▢ Scheduler
y BroadcastReceiver
Pregunta 3
¿Qué API se usa para agregar restricciones a un objeto WorkRequest
?
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
Comienza la siguiente lección:
Para obtener vínculos a otros codelabs de este curso, consulta la página de destino de los codelabs de Conceptos básicos de Kotlin para Android.