Cómo observar el progreso intermedio de trabajadores

WorkManager tiene compatibilidad integrada para establecer y observar el progreso intermedio de los trabajadores. Si el trabajador se estaba ejecutando mientras la app estaba en primer plano, esta información también se puede mostrar al usuario con las APIs que muestran el LiveData de WorkInfo.

ListenableWorker ahora admite la API de setProgressAsync(), que le permite conservar el progreso intermedio. Estas API permiten a los desarrolladores establecer un progreso intermedio que la IU puede observar. El progreso se representa con el tipo Data, que es un contenedor serializable de propiedades (similar a input y output, y sujeto a las mismas restricciones).

La información de progreso solo se puede observar y actualizar mientras se ejecuta ListenableWorker. Se ignoran los intentos de establecer el progreso en un ListenableWorker después de completar su ejecución.

También puedes observar la información del progreso con uno de los métodos getWorkInfoBy…() o getWorkInfoBy…LiveData(). Estos métodos devuelven instancias de WorkInfo, que tiene un método getProgress() nuevo que devuelve Data.

Actualización del progreso

Para los desarrolladores de Java que usan un ListenableWorker o un Worker, la API setProgressAsync() muestra un ListenableFuture<Void>; la actualización del progreso es asíncrona, dado que el proceso de actualización implica almacenar información de progreso en una base de datos. En Kotlin, puedes usar la función de extensión setProgress() del objeto CoroutineWorker para actualizar la información de progreso.

En este ejemplo, se muestra un ProgressWorker. El Worker establece su progreso en 0 cuando comienza y, cuando se completa, actualiza el valor de progreso a 100.

Kotlin

import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.WorkerParameters
import kotlinx.coroutines.delay

class ProgressWorker(context: Context, parameters: WorkerParameters) :
    CoroutineWorker(context, parameters) {

    companion object {
        const val Progress = "Progress"
        private const val delayDuration = 1L
    }

    override suspend fun doWork(): Result {
        val firstUpdate = workDataOf(Progress to 0)
        val lastUpdate = workDataOf(Progress to 100)
        setProgress(firstUpdate)
        delay(delayDuration)
        setProgress(lastUpdate)
        return Result.success()
    }
}

Java

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class ProgressWorker extends Worker {

    private static final String PROGRESS = "PROGRESS";
    private static final long DELAY = 1000L;

    public ProgressWorker(
        @NonNull Context context,
        @NonNull WorkerParameters parameters) {
        super(context, parameters);
        // Set initial progress to 0
        setProgressAsync(new Data.Builder().putInt(PROGRESS, 0).build());
    }

    @NonNull
    @Override
    public Result doWork() {
        try {
            // Doing work.
            Thread.sleep(DELAY);
        } catch (InterruptedException exception) {
            // ... handle exception
        }
        // Set progress to 100 after you are done doing your work.
        setProgressAsync(new Data.Builder().putInt(PROGRESS, 100).build());
        return Result.success();
    }
}

Observación del progreso

Para observar la información del progreso, usa los métodos getWorkInfoById y obtén una referencia a WorkInfo.

A continuación, se muestra un ejemplo que usa getWorkInfoByIdFlow para Kotlin y getWorkInfoByIdLiveData para Java.

Kotlin

WorkManager.getInstance(applicationContext)
      // requestId is the WorkRequest id
      .getWorkInfoByIdFlow(requestId)
      .collect { workInfo: WorkInfo? ->
          if (workInfo != null) {
              val progress = workInfo.progress
              val value = progress.getInt("Progress", 0)
              // Do something with progress information
          }
      }

Java

WorkManager.getInstance(getApplicationContext())
     // requestId is the WorkRequest id
     .getWorkInfoByIdLiveData(requestId)
     .observe(lifecycleOwner, new Observer<WorkInfo>() {
             @Override
             public void onChanged(@Nullable WorkInfo workInfo) {
                 if (workInfo != null) {
                     Data progress = workInfo.getProgress();
                     int value = progress.getInt(PROGRESS, 0)
                     // Do something with progress
             }
      }
});

Para obtener más documentación sobre la observación de objetos Worker, lee Estados y observación de los trabajos. Para obtener información sobre cómo obtener el stopReason cuando el trabajo finaliza de forma inesperada, consulta Observa el estado del motivo de detención.