Como migrar do GCMNetworkManager para o WorkManager

Este documento explica como migrar apps para a biblioteca de cliente do WorkManager a fim de executar operações em segundo plano, em vez de usar a biblioteca do GCMNetworkManager. A maneira preferencial de um app programar jobs em segundo plano é usar o WorkManager. Ao incluir também a biblioteca GCM do WorkManager, você pode permitir que o WorkManager use o GCM para programar tarefas durante a execução em dispositivos Android com API de nível 22 ou versões mais antigas.

Migrar para o WorkManager

Se o app usa atualmente o GCMNetworkManager para realizar operações em segundo plano, siga estas etapas para migrar para o WorkManager.

Nas etapas a seguir, presumimos que você esteja começando com o seguinte código GCMNetworkManager, que define e programa sua tarefa:

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);

Neste exemplo, supomos que MyUploadService define a operação de upload 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;
    }
}

Incluir as bibliotecas do WorkManager

Para usar as classes do WorkManager, você precisa adicionar a biblioteca do WorkManager às suas dependências de compilação. Você também precisa adicionar a biblioteca GCM do WorkManager, que permite que o WorkManager use o GCM para programar jobs quando o app está em execução em dispositivos não compatíveis com o JobScheduler (ou seja, dispositivos com API de nível 22 ou versões mais antigas). Para ver mais detalhes sobre como adicionar as bibliotecas, consulte Primeiros passos com o WorkManager.

Modificar o manifesto

Ao implementar o GCMNetworkmanager, você adicionou uma instância de GcmTaskService ao manifesto do app, conforme descrito na documentação de referência do GcmNetworkManager. GcmTaskService analisa a tarefa recebida e a delega ao gerenciador de tarefas. O WorkManager gerencia a delegação de tarefas para o worker. Assim, você não precisa mais de uma classe para fazer isso. Basta remover GcmTaskService do manifesto.

Definir o worker

Sua implementação do GCMNetworkManager define uma OneoffTask ou RecurringTask, que especifica apenas que trabalho precisa ser feito. É necessário reescrever isso como um Worker, conforme documentado em Como definir suas solicitações de trabalho.

O código GCMNetworkManager de amostra define uma tarefa myTask. O equivalente ao WorkManager é semelhante a este:

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()
    }
}

Há algumas diferenças entre a tarefa do GCM e o Worker:

  • O GCM usa um objeto TaskParams para transmitir parâmetros para a tarefa. O WorkManager usa dados de entrada, que você pode especificar na WorkRequest, conforme descrito na documentação do WorkManager para Definir entrada/saída para sua tarefa. Em ambos os casos, você pode transmitir pares de chave-valor especificando os parâmetros persistentes necessários para a tarefa.
  • O GcmTaskService indica sucesso ou falha retornando sinalizações como GcmNetworkManager.RESULT_SUCCESS. Um Worker do WorkManager sinaliza os resultados usando um método ListenableWorker.Result, como ListenableWorker.Result.success(), e retornando o valor de retorno desse método.
  • Como mencionamos, você não define as restrições ou tags ao definir o Worker, mas faz isso na próxima etapa, ao criar a WorkRequest.

Programar a solicitação de trabalho

Definir um Worker especifica o que é necessário fazer. Para especificar quando o trabalho será feito, é necessário definir a WorkRequest:

  1. Crie uma OneTimeWorkRequest ou PeriodicWorkRequest e defina as restrições desejadas especificando quando a tarefa será executada, bem como as tags para identificar seu trabalho.
  2. Transmita a solicitação a WorkManager.enqueue() para que a tarefa fique na fila para execução.

Por exemplo, a seção anterior mostrou como converter uma OneoffTask em um Worker equivalente. No entanto, esse Worker não incluiu as restrições de execução e a tag do objeto OneoffTask. Em vez disso, definimos as restrições e o ID da tarefa quando criamos a WorkRequest. Também especificaremos que a tarefa só poderá ser executada se houver uma conexão de rede. Você não precisa solicitar explicitamente uma conexão de rede com o GCMNetworkManager, porque ele requer essa conexão por padrão. O WorkManager só requer uma conexão de rede quando você adiciona especificamente essa restrição. Depois de definir a WorkRequest, nós a colocamos na fila com o 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);

Mapeamentos de API

Esta seção faz um mapeamento de como alguns recursos e restrições do GCMNetworkManager são equivalentes aos do WorkManager.

Mapeamentos de restrições

O GCMNetworkManager permite que você defina várias restrições relativas a quando sua tarefa será executada. Na maioria dos casos, há uma restrição do WorkManager equivalente. Esta seção lista os equivalentes.

Defina restrições para as tarefas do GCMNetworkManager chamando o método apropriado no objeto Builder da tarefa. Por exemplo, você pode definir um requisito de rede chamando Task.Builder.setRequiredNetwork().

No WorkManager, você cria um objeto Constraints.Builder e chama os métodos dele para definir restrições, por exemplo, Constraints.Builder.setRequiredNetworkType()). Em seguida, usa o Builder para criar um objeto Constraints que pode ser anexado à solicitação de trabalho. Para ver mais informações, consulte Como definir suas solicitações de trabalho.

Restrição do GCMNetworkManager Equivalente do WorkManager Notes
setPersisted() Não obrigatório Todos os jobs do WorkManager são mantidos durante a reinicialização do dispositivo.
setRequiredNetwork() setRequiredNetworkType() Por padrão, o GCMNetworkManager requer acesso à rede. Por padrão, o WorkManager não requer acesso à rede. Se o job exigir acesso à rede, use setRequiredNetworkType(CONNECTED) ou defina um tipo de rede mais específico.
setRequiresCharging()

Outros mapeamentos

Além das restrições, há outras configurações que você pode aplicar às tarefas do GCMNetworkManager. Esta seção lista a maneira correspondente de aplicar essas configurações a um job do WorkManager.

Tags

Todas as tarefas do GCMNetworkManager precisam ter uma string de tag, que você define chamando o método setTag() do Builder. Os jobs do WorkManager são identificados de forma exclusiva por um ID gerado automaticamente pelo WorkManager. É possível receber esse ID chamando WorkRequest.getId(). Além disso, as solicitações de trabalho podem ter uma ou mais tags. Para definir uma tag para o job do WorkManager, chame o método WorkRequest.Builder.addTag() antes de usar esse Builder para criar a WorkRequest.

No GCMNetworkManager, é possível chamar setUpdateCurrent() para especificar se a tarefa precisa substituir qualquer tarefa existente com a mesma tag. A abordagem equivalente do WorkManager é colocar a tarefa em fila chamando enqueueUniqueWork() ou enqueueUniquePeriodicWork(). Se você usar esses métodos, dê um nome exclusivo ao job e especifique como o WorkManager processará a solicitação quando já houver um job pendente com esse nome. Para ver mais informações, consulte Como gerenciar um trabalho exclusivo.

Parâmetros da tarefa

É possível transmitir parâmetros para um job do GCMNetworkManager chamando Task.Builder.setExtras() e transmitindo um Bundle que contenha os parâmetros. O WorkManager permite que você transmita um objeto Data para o job do WorkManager, com os parâmetros como pares de chave-valor. Para mais detalhes, consulte Atribuir dados de entrada.