Cómo ejecutar subprocesos en Worker

Cuando usas un objeto Worker, WorkManager llama automáticamente a Worker.doWork() en un subproceso en segundo plano. El subproceso en segundo plano proviene del Executor especificado en Configuration de WorkManager. De manera predeterminada, WorkManager configura un Executor por ti, pero también puedes personalizar el tuyo. Por ejemplo, puedes compartir un Executor en segundo plano existente en tu app, crear un Executor de un solo subproceso para asegurarte de que todo tu trabajo en segundo plano se ejecute en serie, o incluso especificar un ThreadPool con un recuento de subprocesos diferente. Para personalizar el Executor, asegúrate de haber habilitado la inicialización manual de WorkManager. Cuando configuras WorkManager, puedes especificar tu Executor de la siguiente manera:

Kotlin

    WorkManager.initialize(
        context,
        Configuration.Builder()
            .setExecutor(Executors.newFixedThreadPool(8))
            .build())
    

Java

    WorkManager.initialize(
        context,
        new Configuration.Builder()
            .setExecutor(Executors.newFixedThreadPool(8))
            .build());
    

A continuación, se muestra un ejemplo de un trabajador simple que descarga el contenido de algunos sitios web de forma secuencial:

Kotlin

    class DownloadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {

        override fun doWork(): ListenableWorker.Result {
            for (i in 0..99) {
                try {
                    downloadSynchronously("https://www.google.com")
                } catch (e: IOException) {
                    return ListenableWorker.Result.failure()
                }
            }

            return ListenableWorker.Result.success()
        }
    }
    

Java

    public class DownloadWorker extends Worker {

        public DownloadWorker(Context context, WorkerParameters params) {
            super(context, params);
        }

        @NonNull
        @Override
        public Result doWork() {
            for (int i = 0; i < 100; ++i) {
                try {
                    downloadSynchronously("https://www.google.com");
                } catch (IOException e) {
                    return Result.failure();
                }
            }

            return Result.success();
        }

    }

    

Ten en cuenta que Worker.doWork() es una llamada síncrona. Se espera que hagas la totalidad del trabajo en segundo plano de forma bloqueada y que la termines cuando el método finalice. Si llamas a una API asíncrona en doWork() y muestras un Result, es posible que la devolución de llamada no funcione correctamente. Si te encuentras en esta situación, considera usar un ListenableWorker (consulta Cómo ejecutar subprocesos en ListenableWorker).

Cuando un Worker que se encuentra actualmente en ejecución se detiene por algún motivo, recibe una llamada a Worker.onStopped(). Anula este método o llama a Worker.isStopped() para verificar tu código y liberar recursos cuando sea necesario. Cuando se detenga el Worker del ejemplo anterior, si se encuentra en el medio de su ciclo de descarga de elementos, continuará haciéndolo aunque se haya detenido. Para optimizar este comportamiento, puedes hacer lo siguiente:

Kotlin

    class DownloadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {

        override fun doWork(): ListenableWorker.Result {
            for (i in 0..99) {
                if (isStopped) {
                    break
                }

                try {
                    downloadSynchronously("https://www.google.com")
                } catch (e: IOException) {
                    return ListenableWorker.Result.failure()
                }

            }

            return ListenableWorker.Result.success()
        }
    }
    

Java

    public class DownloadWorker extends Worker {

        public DownloadWorker(Context context, WorkerParameters params) {
            super(context, params);
        }

        @NonNull
        @Override
        public Result doWork() {
            for (int i = 0; i < 100; ++i) {
                if (isStopped()) {
                    break;
                }

                try {
                    downloadSynchronously("https://www.google.com");
                } catch (IOException e) {
                    return Result.failure();
                }
            }

            return Result.success();
        }
    }
    

Una vez detenido un Worker, no importa lo que muestres de Worker.doWork(); se ignorará el Result.