ProgressDialog deprecated, e agora?

Alex Felipe
CollabCode
Published in
6 min readJan 17, 2018
Ferramentas antigas

A partir do SDK 26 do Android, a classe ProgressDialog ficou deprecated (obseleta), gerando dúvidas entre diversos devs que utilizam essa solução em cenários onde a execução não é imediata, como por exemplo, ao enviar requisições para uma API.

Na própria documentação, somos informados que o motivo é pelo fato do ProgressDialog segurar o usuário fazendo com que ele não consiga interagir com a App

“Então qual abordagem devemos considerar para lidar com esse tipo de situação?”

Além desta informação, a documentação sugere o uso do ProgressBar para substituir o ProgressDialog. Sendo assim, vamos implementar um exemplo no qual faremos uso do ProgressBar.

Projeto de exemplo

Neste artigo farei uso do Ceep, um projeto que desenvolvi em alguns dos meus posts sobre Android onde compartilho no meu agregador de artigos de Kotlin:

Sendo mais específico, vou usar como base a quarta parte da série de Retrofit com Kotlin.

Contextualizando a situação

Neste projeto fizemos uma App na qual realiza a listagem, inserção e alteração de notas. Entretanto, todas as ações realizadas não possuem algum tipo de feedback no qual indique, por exemplo, que está acontecendo algum tipo de carregamento.

Sendo assim, o nosso objetivo será adicionar esse tipo de comportamento utilizando o ProgressBar.

Adicionando o ProgressBar no layout

Como primeiro passo, precisamos adicionar o ProgressBar no layout onde queremos que ele apareça, nesse caso é no activity_note_list:

Adicionando o ProgressBar no layout

Repare que já foi atribuido o id note_list_progress para que possamos buscá-lo na Activity e realizar a configuração desejada. Ao executarmos a App apenas com essa modificação, temos o seguinte resultado:

Lista de notas com o Progress Bar carregando

Por mais que o ProgressBar esteja aparecendo, note que não é um comportamento esperado, pois além de começar a carregar sem um motivo específico, ele não desaparece!

Considerações durante a implementação do ProgressBar

Em outras palavras, ao declarar um ProgressBar precisamos levar algumas considerações:

  • Ele não deve aparecer sem um motivo;
  • Precisamos mostrá-lo apenas se uma ação não tiver um tempo de finalização determinado;
  • Após finalizar a execução do processo que pode demorar, é necessário fazer com que o ProgressBar desapareça.

Considerando os detalhes listados, vamos resolver o primeiro deles. Esse é bem simples, basta apenas modificar o visibility diretamente no XML:

<ProgressBar
android:id="@+id/note_list_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />

Apenas com essa modificação temos nossa App fica volta ao estado de antes:

App com o ProgressBar sem a visibilidade

Configurando o ProgressBar

Mas agora entramos no caso que precisamos pensar em qual momento podemos acionar o ProgressBar, ou seja, em situações que podem demorar. Uma primeira abordagem seria no momento em que tentamos enviar uma nota para o servidor.

Entretanto, do jeito que o nosso Web Client foi implementado, não somos capazes de executar uma ação em um momento antes da requisição ser realizada.

Em outras palavras, precisamos aplicar alguma técnica para permitir esse tipo de ação! E agora?

Adicionando uma Higher-Order Function pré-execução

Uma possibilidade é adicionando mais uma HOF que vai servir apenas para executar alguma ação antes da requisição ser chamada:

Executando a HOF antes de chamar a função de inserção do Web Client

Repare que executamos a HOF de pré-ação antes de chamar o insert do Web Client. Após esse ajuste, na Activity, precisamos implementar a HOF:

Implementando a HOF de pré-execução do Dialog

Perceba que para apresentar o ProgressBar basta apenas modificar o valor do atributo visibility novamente. É válido observar que na chamada do add() precisamos mandar duas HOFs:

  • 1º Ação antes de realizar a requisição.
  • 2º Ação ao receber a resposta de nota criada.

Executando a App e tentando adicionar uma nota, temos o seguinte resultado:

Note que o ProgressBar aparece logo depois de tocar no botão SAVE, porém com um comportamento um tanto quanto não esperado, pois ele aparece e não some!

Isso significa que após finalizar a requisição, precisamos esconder novamente o ProgressBar! Como podemos fazer isso?

Uma abordagem seria realizar esse procedimento diretamente na expressão lambda quando recebemos a nota como resposta:

fab_add_note.setOnClickListener {
NoteDialog( window.decorView as ViewGroup, this)
.add({
note_list_progress.visibility = ProgressBar.VISIBLE
}) {
notes.add(it)
configureList()
note_list_progress.visibility = ProgressBar.GONE
}
}

Ao testarmos novamente, ele funciona perfeitamente, entretanto, quando colocamos, por exemplo, no modo avião (que perde todas as conexões) novamente o ProgressBar não desaparece:

App no modo avião ainda mantém o ProgressBar rodando

Isso significa que a nossa pós execução só acontece apenas em situações que dão certo! Ou seja, independentemente da requisição falhar ou responder com sucesso, ao ser finalizada, a ação precisa ser executada!

Criando uma HOF de pós-execução do Callback

Para isso, podemos criar uma HOF que vai indicar a finalização de execução:

Executando a HOF de finalização tanto na resposta como também na falha

Veja que dentro da função insert(), além das HOFs de sucesso e falha, agora recebemos a de finalização que é executada logo depois de ambas as HOFs. Então, na classe de Dialog, precisamos enviar a HOF para o Web Client:

Adicionando a HOF de finalização e enviando para o Web Client

Note que ao invés de executar a HOF, estamos enviando-a via parâmetro para a função do WebClient. Na Activity, basta apenas executarmos a ação desejada:

fab_add_note.setOnClickListener {
NoteDialog(window.decorView as ViewGroup, this)
.add({
note_list_progress.visibility = ProgressBar.VISIBLE
}, {
note_list_progress.visibility = ProgressBar.GONE
}) {
notes.add(it)
configureList()
}
}

Desta maneira não temos mais a necessidade de executar a ação na HOF que devolve uma nota criada! Testando a App novamente tanto online como também offline, temos o seguinte resultado:

Veja que agora, a requisição sendo bem sucedida ou não, o ProgressBar aparece e também some!

É importante ressaltar que pode ser que o ProgressBar nem apareça dependendo da velocidade da requisição. Para garantir a aparição do mesmo, eu adicionei um delay proposital de 1 segundo.

É válido mencionar que já existe uma implementação de ProgressBar já preparada para esse tipo de comportamento que é ContentLoadingProgressBar.

Código fonte

Caso tenha alguma dúvida ou simplesmente queira consultar o código desenvolvido durante o artigo, fique à vontade em consultar o repositório do GitHub:

Para saber mais

Por mais que esse exemplo seja funcional, ainda existem diversos detalhes importantes para mantermos uma implementação mais consistente, como por exemplo:

  • Implementação das HOFs: Veja que não é tão claro o que implementamos quando temos mais de uma HOF, o exemplo mais crítico acontece na chamada da função add() do Dialog que recebe 3 HOFs e não sabemos, logo de cara, o que cada uma delas fazem…
  • Obrigação de implementar as funções de pré execução e finalização: Nesse caso faz sentido para implementarmos ambas HOFs, porém, nem sempre esse tipo de implementação se faz necessário, ou seja, aplicar uma técnica na qual deixa esse tipo de implementação opcional é bem mais interessante.
  • Reutilização de comportamento: Se tentarmos utilizar o comportamento de pré e pós execução nas outras ações do Web Client, somos obrigados a enviar novamente a HOF de finalização ou até mesmo implementar a de pré-execução no código que vai chamar o Web Client… Isso significa que faz muito mais sentido centralizar esses comportamentos.

Todos esses detalhes são conteúdos o suficiente para um próximo artigo! Nem precisa falar que já está em palta, né?

Um outro ponto importante é que existem diversas variações do ProgressBar para cenários distintos, recomendo que realize uma pesquisa para identificar a que melhor lhe atende 😉

Conclusão

Neste artigo vimos como podemos implementar o ProgressBar que é uma alternativa ao ProgressDialog que agora é depreciado…

Considerando o nosso projeto base, vimos que existem diversas peculiaridades, porém, o conceito básico ainda é mantido.

Inicialmente o ProgressBar fica escondido, então, ele aparece quando é necessário, mas, quando finalizar a tarefa, precisamos fazer com que ele suma novamente 😄

O que achou dessa abordagem para apresentar comportamentos de carregamento? Compartilhe comigo nos comentários!

--

--