Loading Dialog no Android

Loading Dialog no Android

Novamente dando umas pinceladas no Android agora mostro como criar um loading enquanto alguma tarefa ocorre em background, ideal para requisições a APIs e consultas longas.

Do que precisaremos

  • IDE Eclipse;
  • Android SDK instalado e configurado no eclipse;
  • Um AVD (Android Virtual Device) ou um smartphone plugado via USB, reconhecido pelo Sistema Operacional e pelo Eclipse, e ativado o modo desenvolvedor;
  • Um mínimo de conhecimento em Java e/ou ambientação com o desenvolvimento em Android.

Caso não atenda todos os requisitos acima por favor leia este artigo do Viva o Linux que vou levar em consideração de que você já tenha no mínimo feito o que fora apresentado por lá pelo menos uma vez na vida.

Abordarei somente uma Activity sem nada demais, afinal de contas é apenas um exemplo do funcionamento e não uma implementação real.

 

Em que situações utilizar um loading?

Um loading nada mais é que um Dialog para exibir alguma informação de status para o usuário. Vou citar alguns exemplos que podem e alguns deles que devem exibir um loading:

  • Consulta em um banco de dados com muitos registros
  • Processamento dos dados após uma consulta (por ter de montar algumas telas adicionais pode ser demorado)
  • Requisições à WebServices (obrigatório em meu ver)
  • Limpeza de dados
  • Manutenção do app

Em resumo toda e qualquer ação que não ocorra instantaneamente deve exibir um status ao usuário para que ele saiba que algo está acontecendo. Presenciei isto na prática, tenho um sistema de finanças pessoais que segue uma planilha de orçamento doméstico da BM&F Bovespa onde tinha somente o acesso via browser. Decidi criar um app para poder incluir meus gastos diários e nada mais justo que utilizar todo o histórico que já possuo. Criei uma API para que através do celular eu consiga cadastrar uma despesa ou entrada de dinheiro, bem simples, clean e somente isto, incluir ganhos e gastos. Toda a parte de relatórios e detalhamento permanece no sistema web. Nos primeiros testes percebi que em momentos o servidor respondia quase que instantaneamente e exibia a mensagem de despesa adicionada com sucesso e em outros levava 2, 3 chegou a incríveis 10 segundos para devolver a resposta ao app (quando no 3G). Frente a isto vi a necessidade de mesmo que seja somente eu e minha esposa utilizando dar um feedback de que algo está acontecendo.

 

Métodos

Utilizei dois métodos para solucionar o problema, um certamente que duvidoso e outro correto. Vou mencionar o duvidoso somente para vocês saberem quais foram minhas alternativas.

O primeiro método que utilizei foi como comumente fazemos no mundo web, exibimos um loading, enquanto normalmente realizamos uma requisição via ajax para onde quer que seja enquanto isto o loading permanece na tela. Tomei uma atitude parecida, exibi o loading, dei uma pausa de 2 segundos e ai enviei a requisição à API. Certamente que isto resolveu no entanto não ficou elegante. Isto porque o loading era exibido mas 2 segundos depois o mesmo travava e ficava na mesma posição até que a requisição à API tivesse uma resposta. Funcionou mas…

Precisava de algo melhor. E nada melhor que utilizar uma thread diferente para isso. Em resumo, tudo o que eu já tinha feito permaneceu exatamente do mesmo jeito, mudando apenas a remoção do temporizador e adição de uma nova thread. Agora assim que clicado no botão que realizará a chamada à API, o loading é instantaneamente exibido e permanece em execução até o momento que obtenho a resposta da API. Neste caso se a resposta vier instantaneamente o loading é exibido por uma fração de segundo, no entanto se por algum motivo a resposta demorar demais, o loading permanece “trabalhando”.

 

Exemplo – show me the code

Criaremos apenas o esqueleto da activity e adicionaremos os itens pouco a pouco.

public class MainActivity extends Activity {
 private EditText campoDeValor; private EditText campoDeNomeDaDespesa; private EditText campoDeComplemento; private String valorFinal; private String despesa; private String complemento;

    @Override 
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_xml);

        // Necessário para requisições Http
        if (android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = 
              new StrictMode.ThreadPolicy.Builder()
                    .permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }

        gerarBotaoEAcoes();
   }
}

No método gerar botão e ações vamos carregar os inputs e o botão que dará a possibilidade de realizar um cadastro.

public void gerarBotaoEAcoes() {
    final Button btnCadastrarDepesa = 
      (Button) findViewById(R.id.botao_de_cadastro);

    btnCadastrarDespesa.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            campoDeValor = (EditText) findViewById(R.id.valor);
            campoDeNomeDaDespesa = 
              (EditText) findViewById(R.id.descricao);
            campoDeComplemento = 
              (EditText) findViewById(R.id.complemento);

            valorFinal = campoDeValor.getText().toString();
            despesa = campoDeNomeDaDespesa.getText().toString();
            complemento = campoDeComplemento.getText().toString();

            /* Sem realizar tratamento algum, apenas 
                prosseguindo no exemplo */

            gravaDespesa(valorFinal, despesa, complemento);

        }
    });
}

Naturalmente que teremos de criar o método para salvar a despesa enviando os dados fornecidos para a API.

public void gravarDespesa(final String valorFinal, 
       final String despesa, final String compelemento) {

    // aqui começamos a exibir o loading
    final ProgressDialog dialog = 
                new ProgressDialog(MainActivity.this);
    dialog.setMessage("Enviando dados... aguarde");
    dialog.setIndeterminate(false);
    dialog.setCanceledOnTouchOutside(true);
    dialog.setCancelable(true);
    dialog.show();

    new Thread(new Runnable() {

        // O processamento deve ocorrer em "run"

        @Override
        public void run() {
           responseOk = realizaRequisicao(
               valorFinal, despesa, complemento);
        }

        // a resposta deve ser exibida em "runOnUIThread"

        public void runOnUIThread(new Runnable() {

            @Override
            public void run(){
               // e aqui encerramos o loading
               dialog.dismiss();

               String mensagem = "Não foi possível cadastrar a " +
                        "despesa, por favor tente novamente.";

               if( responseOk.equals(true) ) {
                   mensagem = "Despesa adicionada com sucesso!";
               }

               /* Exibindo a mensagem de status da requisição 
                 em um toast apenas para simplificar */

               Toast.makeText(
                   MainActivity.this,
                   "Informação: rn" + mensagem,
                   Toast.LENGTH_LONG
               ).show();
            }           
        });

    });
}

Obviamente que você pode perceber que será necessário criar mais um método, o realizaRequisição. Como não é o foco deste post, apenas o criarei retornando um true de imediato.

public Boolean realizaRequisicao(String valorFinal, 
    String despesa, String complemento) { return true; }

Por enquanto é isto, espero que este post seja útil para quem mais precisar criar um loading e acabar enfrentando as mesmas dificuldades que encontrei (não saber ao certo como proceder). Lembre-se, exibir um status ao usuário de seu App/site/sistema é longe de uma questão visual mas sim de usabilidade. Caso não concorde com o que acabei de dizer sugiro uma leitura sobre UX Design que com certeza sua opinião mudará (se estiver aberto à mudanças claro).

Interesse em TDD?

Então meu livro é perfeito pra você!

Pra ficar melhor ainda, tenho um cupom de 15% de desconto. Clique em “Conheça meu livro” e pegue o seu!

, , , , , ,
Post anterior
ACL em PHP com o CakePHP
Próximo post
Um sonho se torna realidade, antecipadamente

Posts Relacionados

Menu