terça-feira, outubro 30, 2012

Desenvolvendo para o Android: AlertDialog

Às vezes é necessária uma interação muito simples com o operador, como pedir uma confirmação ou apresentar um aviso. Nestas horas, AlertDialog pode ser uma opção mais simples que criar uma Activity. Existem, como sempre, algumas pegadinhas.


Síncrono x Assíncrono

Quem está acompanhando esta série de posts já deve estar cansando das minhas menções ao assincronismo na programação para Android. No Android nunca o seu código fica parado no meio de um método aguardando uma interação do usuário. Existem bons motivos para isto, mas é particularmente chato nestas interações simples.

A Microsoft resolve isto no Windows através das funções DialogBox e MessageBox. Estas funções possuem internamente um "message loop" para tratar as interações que ocorrem durante a espera. Não é uma solução exatamente limpa, mas permite coisas extremamente simples como:
if (MessageBox (hDlg, "Anexar detalhes?",
    szAppName, MB_YESNO | MB_ICONQUESTION) == IDYES)
{
    AnexaDetalhes();
}
EnviaMensagem ();
A execução deste trecho pára aguardando o operador selecionar Sim ou Não e depois continua normalmente.

No Android não dá para fazer isto. O que gera bastante discussão. E é claro que alguém achou uma forma de fazer usando APIs internas (não recomendo usar este código!).

The Android Way

Como no Windows, um dialog no Android é uma janela que normalmente não ocupa toda a tela e é usada para o operador tomar uma decisão ou fornecer uma informação necessária para continuar a execução de uma tarefa.  A classe Dialog é a classe base para as classes que implementam dialogs; ao invés de ser instanciada diretamente deve ser utilizada uma das classes derivadas. AlertDialog é a mais comum delas.

 AlertDialog é uma classe bastante flexível em termos do conteúdo da janela apresentada. A janela é composta por três partes:
  • Um título (opcional).
  • O conteúdo, que pode ser uma mensagem, uma lista ou (com um pouco mais de trabalho) qualquer coisa.
  • Os botões de seleção, que podem ser até três.
A forma como se constrói um diálogo é um pouco esquisita. Você cria primeiro um objeto do tipo AlertDialog.Builder. Depois você chama os métodos deste objeto para acrescentar os elementos e definir os Event Listeners. Aí você chama o método create para criar o diálogo. Finalmente, você chama o método show do diálogo para ele ser apresentado e executado. Vejamos um exemplo parecido com o que vimos para o Windows:
AlertDialog.Builder builder = 
        new AlertDialog.Builder(TesteAlertActivity.this);
builder.setTitle(R.string.app_name);
builder.setMessage(R.string.msg_confirma);
builder.setPositiveButton(R.string.sim, new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
        AnexaDetalhes();
        EnviaMensagem();
    }
});
builder.setNegativeButton(R.string.nao, new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
        EnviaMensagem();
    }
});
AlertDialog dialog = builder.create();
dialog.show();
O mais importante nisto tudo é entender que a execução não para em dialog.show(). Você só vai saber o que o operador decidiu quando um dos event listeners for chamado. No caso isto obrigou a ter duas chamadas separadas a EnviaMensagem, uma em cada listener.

Para confundir um pouco mais, é comum aproveitar o fato dos métodos de AlertDialog,Builder retornarem um referência ao próprio objeto para compactar um pouco mais o código:
final AlertDialog dialog =
    new AlertDialog.Builder(TesteAlertActivity.this)
    .setTitle(R.string.app_name)
    .setMessage(R.string.msg_confirma)
    .setPositiveButton(R.string.sim, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            AnexaDetalhes();
            EnviaMensagem();
        }
    })
    .setNegativeButton(R.string.nao, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            EnviaMensagem();
        }
    })
    .create();
dialog.show();

É claro que existem bons motivos para escrever tudo isto ao invés de um simples MessageBox, mas bem que o pessoal da Google podia pelo menos manifestar alguma simpatia pelos programadores ao invés de responderem secamente "você não quer fazer isto, faça do jeito certo - o meu".

2 comentários:

Sony Santos disse...

Olá! Ficou faltando a versão Android do código para windows (o 2º bloco de código está vazio). OU é o bloco que aparece logo em seguida (o 3º), o que faz bastante sentido pelo contexto. ;-)

Daniel Quadros disse...

Acertado... o editor do blogger não é exatamente um WYSIWYG e para entrar com o código precisa mudar para o modo HTML; eu acabei me confundindo e esqueci de conferir o preview. Obrigado pelo aviso!