Migración de GCMNetworkManager a WorkManager

En este documento, se explica cómo migrar apps para usar la biblioteca cliente de WorkManager en lugar de la biblioteca de GCMNetworkManager con el fin de realizar operaciones en segundo plano. Por lo general, la forma preferida para hacer que una app programe trabajos en segundo plano es mediante WorkManager. Al incluir también la biblioteca de WorkManager GCM, puedes habilitar WorkManager para usar GCM a fin de programar las tareas cuando se ejecuta en dispositivos Android con un nivel de API 22 o inferior.

Cómo migrar a WorkManager

Si tu app actualmente usa GCMNetworkManager para realizar operaciones en segundo plano, sigue estos pasos a fin de migrar a WorkManager.

En los siguientes pasos, suponemos que estás comenzando con el siguiente código de GCMNetworkManager, que define y programa tu tarea:

Kotlin

val myTask = OneoffTask.Builder()
    // setService() says what class does the work
    .setService(MyUploadService::class.java)
    // Don't run the task unless device is charging
    .setRequiresCharging(true)
    // Run the task between 5 & 15 minutes from now
    .setExecutionWindow(5 * DateUtil.MINUTE_IN_SECONDS,
            15 * DateUtil.MINUTE_IN_SECONDS)
    // Define a unique tag for the task
    .setTag("test-upload")
    // ...finally, build the task and assign its value to myTask
    .build()
GcmNetworkManager.getInstance(this).schedule(myTask)

Java

// In GcmNetworkManager, this call defines the task and its
// runtime constraints:
OneoffTask myTask = new OneoffTask.Builder()
    // setService() says what class does the work
    .setService(MyUploadService.class)
    // Don't run the task unless device is charging
    .setRequiresCharging(true)
    // Run the task between 5 & 15 minutes from now
    .setExecutionWindow(
        5 * DateUtil.MINUTE_IN_SECONDS,
        15 * DateUtil.MINUTE_IN_SECONDS)
    // Define a unique tag for the task
    .setTag("test-upload")
    // ...finally, build the task and assign its value to myTask
    .build();
GcmNetworkManager.getInstance(this).schedule(myTask);

En este ejemplo, se asume que MyUploadService define la operación de carga real:

Kotlin

class MyUploadService : GcmTaskService() {
    fun onRunTask(params: TaskParams): Int {
        // Do some upload work
        return GcmNetworkManager.RESULT_SUCCESS
    }
}

Java

class MyUploadService extends GcmTaskService {
    @Override
    public int onRunTask(TaskParams params) {
        // Do some upload work
        return GcmNetworkManager.RESULT_SUCCESS;
    }
}

Cómo incluir las bibliotecas de WorkManager

Para usar las clases de WorkManager, debes agregar la biblioteca de WorkManager a tus dependencias de compilación. También debes agregar la biblioteca de WorkManager GCM, que permite a WorkManager usar GCM para la programación de trabajos cuando tu app se ejecuta en dispositivos que no admiten JobScheduler (es decir, dispositivos con nivel de API 22 o inferior). Si quieres obtener información detallada para agregar las bibliotecas, consulta Cómo comenzar a usar WorkManager.

Cómo modificar tu manifiesto

Cuando implementaste GCMNetworkmanager, agregaste una instancia de GcmTaskService al manifiesto de la app, como se describe en la documentación de referencia de GcmNetworkManager. GcmTaskService examina la tarea entrante y la delega al controlador de tareas. WorkManager administra la delegación de tareas a tu trabajador, por lo que ya no necesitas una clase que lo haga; simplemente puedes quitar tu GcmTaskService del manifiesto.

Cómo definir al trabajador

Tu implementación de GCMNetworkManager define una OneoffTask o RecurringTask, que especifica exactamente qué trabajo se debe hacer. Debes volver a escribir eso como Worker, como se documenta en Cómo definir tus solicitudes de trabajo.

El código GCMNetworkManager de muestra define una tarea myTask. El equivalente de WorkManager se ve de la siguiente manera:

Kotlin

class UploadWorker(context: Context, params: WorkerParameters)
                        : Worker(context, params) {
    override fun doWork() : Result {
        // Do the upload operation ...
        myUploadOperation()

        // Indicate whether the task finished successfully with the Result
        return Result.success()
    }
}

Java

public class UploadWorker extends Worker {

    public UploadWorker(
        @NonNull Context context,
        @NonNull WorkerParameters params) {
        super(context, params);
    }

    @Override
    public Result doWork() {
      // Do the upload operation ...

      myUploadOperation()

      // Indicate whether the task finished successfully with the Result
      return Result.success()
    }
}

Existen las siguientes diferencias entre la tarea de GCM y Worker:

  • GCM usa un objeto TaskParams para pasar parámetros a la tarea. WorkManager usa datos de entrada, que puedes especificar en WorkRequest, como se describe en la documentación de WorkManager sobre Cómo definir entradas y salidas para tu tarea. En ambos casos, puedes pasar pares clave-valor que especifiquen los parámetros persistentes necesarios para la tarea.
  • El GcmTaskService indica si la operación se realizó correctamente o no con marcas como GcmNetworkManager.RESULT_SUCCESS. Un Worker de WorkManager indica sus resultados mediante un método ListenableWorker.Result, como ListenableWorker.Result.success(), y mostrando el valor de resultado de ese método.
  • Como ya se mencionó, cuando defines el elemento Worker, no estableces restricciones ni etiquetas. Eso lo haces en el paso siguiente, cuando creas el elemento WorkRequest.

Cómo programar la solicitud de trabajo

La definición de Worker especifica qué necesitas hacer. Para especificar cuándo se debe realizar el trabajo, debes definir la WorkRequest:

  1. Crea una OneTimeWorkRequest o PeriodicWorkRequest y establece las restricciones que desees para especificar cuándo se debe ejecutar la tarea y las etiquetas que identifican tu trabajo.
  2. Pasa la solicitud a WorkManager.enqueue() con el objetivo de que la tarea se ponga en cola para su ejecución.

Por ejemplo, en la sección anterior se mostró cómo convertir un elemento OneoffTask en un elemento Worker equivalente. Sin embargo, ese Worker no incluyó las restricciones y la etiqueta de ejecución del objeto OneoffTask. En su lugar, estableceremos las restricciones y el ID de la tarea cuando creemos el elemento WorkRequest. También especificaremos que la tarea no debe ejecutarse a menos que haya una conexión de red. No es necesario que solicites explícitamente una conexión de red con GCMNetworkManager, ya que este requiere la conexión de forma predeterminada. Sin embargo, WorkManager no la requiere a menos que agregues específicamente esa restricción. Una vez que definimos el elemento WorkRequest, lo ponemos en cola con WorkManager.

Kotlin

val uploadConstraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .setRequiresCharging(true).build()

val uploadTask = OneTimeWorkRequestBuilder<UploadWorker>()
    .setConstraints(uploadConstraints)
    .build()
WorkManager.getInstance().enqueue(uploadTask)

Java

Constraints uploadConstraints = new Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .setRequiresCharging(true)
    .build();

OneTimeWorkRequest uploadTask =
        new OneTimeWorkRequest.Builder(UploadWorker.class)
  .setConstraints(uploadConstraints)
  .build();
WorkManager.getInstance().enqueue(uploadTask);

Mapeados de API

En esta sección, se describe cómo se mapean algunas funciones y restricciones de GCMNetworkManager con sus equivalentes de WorkManager.

Mapeado de restricciones

GCMNetworkManager te permite establecer una serie de restricciones que se aplican en el momento de la ejecución de tu tarea. En la mayoría de los casos, existe una restricción equivalente de WorkManager clara. En esta sección, se enumeran esas equivalencias.

Llama al método adecuado en el objeto Builder de la tarea para establecer restricciones en las tareas de GCMNetworkManager. Por ejemplo, puedes establecer un requisito de red llamando a Task.Builder.setRequiredNetwork().

En WorkManager, puedes crear un objeto Constraints.Builder y llamar a los métodos de ese objeto para establecer restricciones (por ejemplo, Constraints.Builder.setRequiredNetworkType())). Luego, usa el compilador a fin de crear un objeto Constraints que puedes adjuntar a la solicitud de trabajo. Para obtener más información, consulta Cómo definir tus solicitudes de trabajo.

Restricción de GCMNetworkManager Equivalente de WorkManager Notas
setPersisted() (no se necesita) Todos los trabajos de WorkManager se conservan después de todos los reinicios del dispositivo.
setRequiredNetwork() setRequiredNetworkType() De manera predeterminada, GCMNetworkManager requiere acceso a la red. WorkManager no necesita acceso a la red de manera predeterminada. Si tu trabajo requiere acceso a la red, debes usar setRequiredNetworkType(CONNECTED) o establecer un tipo de red más específico.
setRequiresCharging()

Otros mapeos

Además de las restricciones, hay otras opciones de configuración que puedes aplicar a las tareas de GCMNetworkManager. En esta sección, se describe la forma correspondiente de aplicar esas opciones a un trabajo de WorkManager.

Etiquetas

Todas las tareas de GCMNetworkManager deben tener una string de etiqueta, que se establece llamando al método setTag() de Builder. Los trabajos de WorkManager se identifican de forma exclusiva mediante un ID, que WorkManager genera automáticamente. Puedes obtenerlo llamando a WorkRequest.getId(). Además, las solicitudes de trabajo pueden tener de forma opcional una o más etiquetas. Para establecer una etiqueta en tu trabajo de WorkManager, llama al método WorkRequest.Builder.addTag() antes de usar ese objeto Builder para crear el WorkRequest.

En GCMNetworkManager, puedes llamar a setUpdateCurrent() para especificar si la tarea debe reemplazar cualquier tarea existente con la misma etiqueta. El enfoque equivalente de WorkManager es poner en cola la tarea llamando a enqueueUniqueWork() o enqueueUniquePeriodicWork(). Si usas estos métodos, le asignas un nombre único al trabajo y también especificas cómo WorkManager debe manejar la solicitud si ya existe un trabajo pendiente con ese nombre. Para obtener más información, consulta Cómo administrar el trabajo único.

Parámetros de la tarea

Para pasar parámetros a un trabajo de GCMNetworkManager, llama a Task.Builder.setExtras() y pásalos dentro de un objeto Bundle. WorkManager te permite pasar un objeto Data que contenga los parámetros como pares clave-valor al trabajo de WorkManager. Para obtener más información, consulta Cómo asignar datos de entrada.