Subscribe to our Newsletter

Receive our news and insights

Blog / Spanish  

Tareas de Android en segundo plano con WorkManager

A Picture of Joel Prada
By:
June 21, 2019 | Topic: Spanish  
Tareas de Android en segundo plano con WorkManager

Como desarrolladores móviles, somos conscientes de que los sistemas operativos móviles están diseñados para funcionar en dispositivos con memorias y baterías limitadas. Además, en el caso de Android, nos vemos obligados a evitar ejecutar operaciones dificultosas en el thread principal (por ejemplo, decodificar una imagen BMP, acceder al disco y realizar solicitudes de red), porque esto podría congelar la pantalla y así ofrecerle una experiencia poco satisfactoria al usuario.

En este sentido, es importante saber cómo trabajar con procesos en segundo plano, ya que esto nos permite realizar tareas en un thread separado, agruparlas o ejecutarlas más tarde, incluso en aquellos supuestos en los que la app no está en primer plano. La sincronización de manera periódica con un servidor o la ejecución de una operación inmediatamente, incluso luego de que el usuario haya dado por finalizada su interacción con la app, son algunos ejemplos de esto. Como consecuencia, esto le permite a la aplicación reducir su consumo de batería, y evita que se bloquee el thread principal. Para lograr entender con qué tipo de situación estamos tratando, podemos usar el Gráfico 1.

Options to work with background tasks

Gráfico 1. Opciones para trabajar con tareas en segundo plano.
Fuente: https://developer.android.com/guide/background/

Algunos recordarán que, desde API level 26 (Android Pie) en adelante, el sistema les impone restricciones a las aplicaciones que se están ejecutando en segundo plano. Sin embargo, como puedes ver en la imagen, hay muchas alternativas disponibles para manejar cada situación que pueda presentarse.

Cuando el usuario inicia una tarea que requiere ser ejecutada inmediata y completamente, se le sugiere que recurra a un Foreground Service. Dicho componente le dice al sistema que la aplicación está haciendo algo importante y que, por lo tanto, no puede ser suprimida. Algunos ejemplos de su uso son los casos de reproducción de música, la realización de una compra, o el registro de datos de sensores. Cuando inicias cualquiera de esas actividades, estas deben tener un principio y un fin explícitos. Más aún, todas deben ser capaces de ser canceladas por el usuario en cualquier momento.

DownloadManager, por su parte, puede llevar a cabo descargas HTTP prolongadas en segundo plano desde un URI para que se descargue a un destino particular. Se encarga de las interacciones HTTP e incluso vuelve a intentar realizar descargas que fracasaron a causa de un crash o porque se produjeron cambios de conexión o se reinició el sistema. Ahora, cuando necesitas ejecutar una tarea en un momento preciso, AlarmManager es la mejor opción. Este inicia la aplicación, si es necesario, para realizar la tarea en el momento determinado. Sin embargo, si no necesitas que la tarea sea ejecutada en un momento específico, WorkManager es la mejor opción.

Si la aplicación debe realizar tareas en algún momento pero no de manera inmediata, WorkManager va a programar esas tareas para el momento más apropiado según los parámetros del sistema. Además, la tarea a realizarse en segundo plano puede ser condicionada por otras cuestiones, como la disponibilidad de red y de energía. Como WorkManager es el tema central de este artículo, a continuación vamos a hacer un análisis a fondo de esa biblioteca.

¿Por qué usar WorkManager?

WorkManager es un componente de arquitectura de Android que forma parte de Android Jetpack. Se trata de una biblioteca de Android que ejecuta en segundo plano procesos diferibles y garantizados cuando se cumplen las restricciones del trabajo. En otras palabras, WorkManager proporciona una API amigable con la batería que engloba años de evolución de las restricciones de comportamiento de Android en segundo plano. WorkManager está destinado a tareas que requieren una garantía de que el sistema operativo las ejecutará incluso si se cierra la app. Sin embargo, es importante resaltar el hecho de que no está desarrollada para ejecutar tareas que requieren una ejecución inmediata o en un momento exacto. Conviene más recurrir a Foreground Service o a AlarmManager para esas situaciones.

Esta biblioteca nos da la posibilidad de establecer algunas condiciones o restricciones que deben cumplirse antes de que se ejecute la tarea, como el nivel de batería, la disponibilidad de red, el estado de carga o el estado de almacenamiento del dispositivo. Más aún, nos permite programar tareas periódicas y cadenas de tareas dependientes complejas. WorkManager, además, admite sin dificultades tareas encadenadas con entrada y salida. El trabajo en segundo plano puede ejecutarse de manera paralela o secuencial, lo cual permite especificar el orden de ejecución. En resumen, WorkManager ofrece los siguientes beneficios:

  • Es compatible con diferentes versiones de SO
    ○ Usa JobScheduler en dispositivos con API 23+
    ○ Usa combinaciones de BroadcastReceiver + AlarmManager en dispositivos con API 14 – 22
  • Recurre a las mejores prácticas para proteger el sistema
  • Soporta tareas únicas asincronizadas y periódicas
  • Admite tareas encadenadas con entrada y salida
  • Permite que se condicione el inicio de la tarea
  • Garantiza la ejecución de la tarea, incluso si se reinicia la aplicación o el dispositivo

Aprendiendo con un ejemplo

Veamos a continuación un ejemplo en el cual construiremos una aplicación simple que blurrea fotos e imágenes, y guarda el resultado en un archivo. Vamos a utilizar la guía de Google’s codelab llamada “Background Work with WorkManager in Kotlin” (Tareas en segundo plano en Kotlin con WorkManager).

Dado que la biblioteca WorkManager ha sido lanzada recientemente para su uso en producción, podemos importarla escribiendo la siguiente línea en nuestro archivo gradle:

implementation "android.arch.work:work-runtime-ktx:2.0.1"

A continuación, vamos a analizar las clases básicas que son importantes a la hora de utilizar esta biblioteca:

  • Worker: Aquí escribimos todas las tareas que queremos ejecutar en segundo plano. Sólo tenemos que extender esta clase y anular el método doWork().
  • WorkRequest: Esta clase representa una solicitud para ejecutar una tarea. En este paso podemos especificar las restricciones del worker. Además, hay dos tipos de WorkRequest: OneTimeWorkRequest y PeriordWorkRequest. El primero sólo se ejecuta una vez, mientras que el segundo se repetirá cíclicamente.
  • WorkManager: Es el responsable de ejecutar y programar el WorkRequest. Programa WorkRequests de manera tal que distribuye la carga entre los diferentes recursos del sistema y respeta las restricciones o condiciones que tú específicas.
  • WorkContinuation: Le permite a los desarrolladores encadenar varios OneTimeWorkRequest, o crear gráficos de dependencias acíclicas arbitrarias. Es posible agregar trabajo dependiente a un WorkContinuation invocando OneTimeWorkRequests, y esto volverá a un nuevo WorkContinuation, como se puede ver en el Fragmento 1.

WorkContinuation example

Fragmento 1. Ejemplo de WorkContinuation.

Como se puede ver en el Gráfico 2, en la aplicación debes seleccionar una imagen y luego elegir una opción de blurreado para aplicar a dicha imagen. Por último, la aplicación programa el blurreo en base a los recursos disponibles, y guarda la imagen al final del proceso, como se puede ver en el Gráfico 3.

The activities of the app

Gráfico 2. La acciones disponibles en la app.

Source: https://codelabs.developers.google.com/codelabs/android-workmanager-kt/index.html?index=..%2F..index#5

The chained work

Gráfico 3. El trabajo en cadena

Fragmento 2. CleanUp Worker.

Como se muestra en el Fragmento 2, el CleanUpWorker elimina cualquier archivo que termina en “.png”, y le muestra una notificación al usuario utilizando un método llamado “makesStatusNotification”, el cual va a durar hasta que el próximo worker inicie.

BlurWorker

Fragmento 3. BlurWorker.

El BlurWorker crea un versión blurreada del bitmap a través de un método estático llamado blurBitmap, y luego se crea un bitmap en un archivo temporario a través de writeBitmapToFile (puedes encontrar ambos métodos en el source code del codelab). Finalmente, se ofrece un output para el URI temporario de la imagen blurreada.

Fragmento 4. SaveImageToFile Worker

El worker SaveImageToFileWorker toma el URI de la imagen desde KEY_IMAGE_URI e intenta almacenarlo. Si la escritura tiene éxito, el URI de la imagen almacenada es devuelto con el mismo KEY_IMAGE_URI, lo que permite que se le muestre la imagen al usuario luego de que haya sido almacenada. Por último, se presiona el botón “Go” como se muestra en el Gráfico 2, y es necesario crear una cadena de tareas con CleanUpWorker, BlurWorker y SaveImageToFileWorkWorker.

The applyBlur method in the BlurViewModel class

Fragmento 5. El método applyBlur en la clase BlurViewModel.

Como se muestra en el Fragmento 5, iniciamos el WorkerContinuation con el CleanUpWorker. Aquí estamos haciendo uso de las cadenas de trabajo únicas de WorkManager, una de sus características más poderosas. Este ejecuta las cadenas de trabajo una por una. Para usar esta característica, se debe usar el beginUniqueWork en lugar de beginWith, y se tiene que proporcionar un id a la cadena (por ejemplo, IMAGE_MANIPULATION_WORK_NAME). Luego, la policy (ExistingWorkPolicy) debe añadirse al builder, el cual puede ser REPLACE, KEEP o APPEND. Como se muestra en el Fragmento 5, se utiliza REPLACE porque si el usuario decide blurrear otra imagen antes de que la imagen actual esté terminada, queremos que se ponga en pausa la actual y se comience a blurrear la imagen nueva.

Luego del primer WorkRequest, vamos a agregar, dependiendo del blurLevel, la cantidad de BlurWorkers que el usuario haya seleccionado. Luego, se aplica enqueue al último worker (SaveImageToFileWorker) y, para empezar con el trabajo, es necesario utilizar el método enqueue en nuestro objeto de continuación.

La restricción RequiresCharging se agrega para el último worker. Además, también es posible agregar restricciones como StorageNotLow, DeviceIdle o BatteryNotLow. De esta manera, si no se cumple con cualquiera de estas restricciones, el Worker no se iniciará. Además, si quieres cancelar un WorkRequest o una cadena de trabajo, puedes hacerlo mediante el método llamado cancelUniqueWork, como se muestra en el Fragmento 6.

Cancel Work method

Fragmento 6. Método Cancel Work.

Conclusiones

Hemos aprendido que WorkManager es una herramienta poderosa. Puede ser útil en varias situaciones en las que queremos ejecutar tareas en segundo plano sin dificultades utilizando los recursos del dispositivo de la mejor manera posible. Tiene algunas ventajas, como por ejemplo, el hecho de que garantiza la ejecución de la tarea, incluso si se reinicia la aplicación o el dispositivo. Sin embargo, como mencionamos al inicio de este artículo, no podemos usar WorkManager en todos los procesos en segundo plano.

Tenemos que asegurarnos de que verdaderamente lo necesitamos, porque si no es así, va a ser más conveniente optar por otra opción, como un Foreground service, DownloadManager o AlarmManager. Otra característica útil es la posibilidad de encadenar tareas usando WorkContinuation, que admite gráficos complejos o la combinación de listas de WorkRequests. En conclusión, WorkManager es una biblioteca que ejecuta tareas diferibles en segundo plano, recurre a las mejores prácticas para proteger el sistema, y garantiza que se ejecuten las tareas en segundo plano cuando se cumplen las restricciones del trabajo. Un consejo extra: si estabas usando la biblioteca Evernote jobs library, deberías comenzar tu transición hacia WorkManager, ya que la reemplaza casi completamente.

Lo que no analizamos

Aquellos lectores que estén interesados en aprender en detalle cómo funciona WorkManager pueden acceder a este artículo. Allí van a ver cómo se manejan los threads y cómo la biblioteca garantiza la ejecución de cualquier tarea.  Además, el artículo explica cómo podemos ver el estado de WorkRequest (Blocked, Enqueued, Running and Succeeded, Failed o Cancelled) usando la biblioteca de Jetpack: LiveData.

Referencias y lectura complementaria

  1. https://developer.android.com/guide/background/
  2. https://android-developers.googleblog.com/2018/12/effective-foreground-services-on-android_11.html
  3. https://medium.com/androiddevelopers/introducing-workmanager-2083bcfc4712
  4. https://medium.com/androiddevelopers/workmanager-basics-beba51e94048
  5. https://codelabs.developers.google.com/codelabs/android-workmanager-kt/index.html?index=..%2F..index#5
The chatbot revolution

Related Services

EXECUTIVE INSIGHTS

Financial  

The changing face of payments, security, and AI in finance

By

November 20 / 2019

1 Stars2 Stars3 Stars4 Stars5 Stars
Loading...

Money 20/20 – Belatrix’s key takeaways on payments, security and AI A couple of weeks ago, Belatrix, now a Globant Division, sponsored one of the largest global financial services...

Read post

HOT
TOPIC