O que é o WorkManager?
No Google IO 2018 foi liberado o Android Jetpack, um conjunto de bibliotecas, ferramentas e orientações arquiteturais para ajudar, tornar rápido e facilitar a criação de aplicativos para Android.
O WorkManger está incluído no Jetpack, mas o que é o WorkManager? É uma API que facilita a especificação de tarefas assíncronas, levando em consideração a periodicidade e as condições em que as tarefas serão executadas. Usando um conjunto de APIs, que falarei abaixo, podemos criar uma tarefa e entregá-la ao WorkManager para execução imediata ou no momento apropriado.

Por exemplo, imagine que nosso aplicativo tenha que fazer o download de um podcast semanalmente. Usando essas classes, você pode configurar esta tarefa, escolher as circunstâncias apropriadas para execução (como “somente enquanto o dispositivo estiver conectado à internet”) e entregá-la ao WorkManager para ser executada quando as condições forem atendidas. Sua tarefa está garantida para ser executada, mesmo se o aplicativo for forçado a sair ou o dispositivo for reinicializado.
O WorkManager consegue escolher qual a melhor forma de executar as tarefas baseadas no estado do aplicativo e no nível da API utilizada. Se ele executar uma tarefa enquanto o aplicativo estiver em execução, poderá fazer isto em uma nova thread no processo do seu aplicativo. Se o aplicativo não estiver em execução, ele vai escolher uma maneira apropriada de agendar a tarefa em segundo plano, levando em consideração o nível da API do dispositivo e das dependências incluídas; neste caso, ele poderá usar JobScheduler, Firebase Job Dispatcher ou AlarmManager.
Agora, vamos ver um pouco do que podemos fazer!

Como usar o WorkManager?
Vamos lá, primeiramente devemos adicionar o WorkManager em nosso aplicativo. Para isto, devemos adicionar no arquivo “build.gradle” da aplicação as seguintes linhas abaixo:
dependencies { def work_version = "1.0.0-alpha01" implementation "android.arch.work:work-runtime:$work_version" implementation "android.arch.work:work-firebase:$work_version" }
O nosso segundo passo é criar o nosso Worker e implementar o método doWork, onde faremos a tarefa. O método doWork retorna um WorkerResult e podemos ter três retornos:
- FAILURE: em caso de falha ou de não conformidades.
- RETRY: significa que houve um erro transitório, ou seja, se o dispositivo perdeu a conexão de rede no meio, então teremos que tentar novamente depois de algum tempo.
- SUCCESS: quando a execução for completada com sucesso.
Logo abaixo, temos um exemplo no qual usamos uma url passada como parâmetro e requisitamos um download ao DownloadManager:
public class DownloadWorker extends Worker { @NonNull @Override public WorkerResult doWork() { String url = getInputData().getString("key_url", ""); if (URLUtil.isValidUrl(url)) { long downloadId = downloadFile(url); Data outputData = new Data.Builder() .putLong("key_download_id", downloadId).build(); setOutputData(outputData); return WorkerResult.SUCCESS; } else { return WorkerResult.FAILURE; } } public long downloadFile(String url) { Long result = -1L; DownloadManager downloadManager = (DownloadManager) getApplicationContext() .getSystemService(Context.DOWNLOAD_SERVICE); if (downloadManager != null) { DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); result = downloadManager.enqueue(request); } return result; } }
Como podemos ver acima, podemos adicionar dados ao retorno do método doWork através do método setOutputData passando um Data como parâmetro.
Por fim, vamos agendar a nossa tarefa, mas antes, deixa eu te mostrar alguns Componentes importantes para fazer isso. Primeiro, temos dois tipos de WorkRequest implementados: OneTimeWorkRequest e PeriodicWorkRequest.
- OneTimeWorkRequest: uma classe que representa uma solicitação para trabalho não repetitivo. Exemplo: fazer o upload de uma foto ao clicar no botão.
- PeriodicWorkRequest: uma classe que representa uma solicitação para trabalhos que tem uma repetição. Exemplo: baixar o podcast toda semana sem que o usuário use o aplicativo.
Logo abaixo temos um exemplo no qual estamos agendando um download ao entrar na activity:
@Override protected void onCreate(Bundle savedInstanceState) { ... Data inputData = new Data.Builder() .putString("key_url", "http://www.awitness.org/prophecy.zip") .build(); Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build(); OneTimeWorkRequest otwRequest = new OneTimeWorkRequest.Builder(DownloadWorker.class) .setInputData(inputData) .setConstraints(constraints).build(); WorkManager.getInstance().enqueue(otwRequest); }
E uma das coisas mais legais é que você pode adicionar Constraints para que a sua task seja executada apenas quando satisfazer essas condições. No exemplo acima, o DownloadWorker será executado apenas quando o device estiver conectado à internet.
Outra coisa legal, é que podemos ficar observando a mudança de estados da nossa tarefa e tomar alguma decisão baseado neles:
LiveData<WorkStatus> status = WorkManager.getInstance().getStatusById(otwRequest.getId()); status.observe(this, new Observer<WorkStatus>() { @Override public void onChanged(@Nullable WorkStatus workStatus) { if (workStatus != null && workStatus.getState().isFinished()) { //TODO: Faca algo; } } });
Gostaria de agradecer ao Rodrigo Perazzo por me encorajar a escrever e revisar meu artigo!