sexta-feira, 17 de junho de 2011

Tarefas assíncronas no Android

Olá pessoal,

Em muitos momentos será necessário a comunicação com um servidor web para fazer a integração da aplicação mobile. Essa atividade deve ser feita em uma Thread separada da UI, entretanto precisamos dar um feedback para o usuário de que essa operação está sendo executada. Para esse tipo de tarefa o Android disponibiliza a classe AsyncTask. Ele permite configurar o que será feito antes, durante e depois da execução de uma tarefa.
No código eu vou acessar a página do dicionário Michaelis para obter a tradução de uma determinada palavra. No onClick do botão, estou iniciando uma nova AsyncTask. Notem que foi passado o conteúdo da caixa de texto como parâmetro pro método execute.
O método downloadArquivo baixará o conteúdo HTML que é gerado pelo site do Michaelis.

public class PrincipalActivity extends Activity
implements OnClickListener {

private String URL_TXT  =
  "http://michaelis.uol.com.br/moderno/portugues/"+
  "index.php?lingua=portugues-portugues&"+
  "typeToSearchRadio=exactly&pagRadio=50&palavra=";
private TextView txtHTML;
private EditText edtTexto;
 
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.teste_async);

  findViewById(R.id.button1).setOnClickListener(this);

  txtHTML = (TextView)findViewById(R.id.textView2);
  edtTexto = (EditText)findViewById(R.id.editText1);
}

public void onClick(View v) {
  new MinhaAsyncTask().execute(
    edtTexto.getText().toString());
}

public String downloadArquivo(String url) {
  HttpURLConnection connection = null;
  InputStream is = null;
  ByteArrayOutputStream bos = null;
  String s = null;
  
  try {
    URL urlAddr = new URL(url);
    connection = (HttpURLConnection)
      urlAddr.openConnection();

    connection.setRequestMethod("GET");
    connection.setDoInput(true);     
    connection.setDoOutput(false);
    connection.connect();
   
    is = connection.getInputStream();
   
    bos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
   
    while ((length = is.read(buffer)) > 0 ) {
      bos.write(buffer, 0, length);
    }
    
    s = new String(bos.toByteArray(), "ISO-8859-1");
   
  } catch (Exception e) {
    e.printStackTrace();
  }  finally {
    try {
      bos.close();
      is.close();
      connection.disconnect();
    } catch (Exception e){}
  }

  return s;
}
 
class MinhaAsyncTask 
  extends AsyncTask <String, Void, String> {

  private ProgressDialog progressDialog;

  protected void onPreExecute() {
    progressDialog = new ProgressDialog(
      PrincipalActivity.this);

    progressDialog.setMessage("Aguarde...");
    progressDialog.show();
  }

  protected String doInBackground(String... v) {
    String s = downloadArquivo(
      URL_TXT + v[0].toString());

    return s;
  }

  protected void onPostExecute(String result) {
    txtHTML.setText(result);
    progressDialog.dismiss();
  }
}
}


Nossa AsyncTask é declarado recebendo 3 valores genéricos. O primeiro é o tipo do dado que será passado como parâmetro na para o método que executará em segundo plano (doInBackground). O segundo é o tipo do dado que pode ser usado para enviar o progresso de alguma execução da thread background (onProgressUpdate). E o último é o tipo de retorno da ação que será realizada em segundo plano.
No nosso caso usamos: uma String, que será a palavra a ser buscada; Void, já que não usarei o progresso com números; e a String que será o HTML lido.

EDITADO 19/06/2012
Para o Android, toda aplicação que possa onerar ou por em risco os dados do usuário deve requerer uma permissão para pode utilizar determinado recurso. No caso da nossa aplicação é a permissão de acesso a internet. Adicione a permissão abaixo dentro da tag do AndroidManifest.xml
<uses-permission
  android:name="android.permission.INTERNET" />

Esse post foi baseado no post sobre AsyncTask do blog Eu, Android e foi enviado pelo meu aluno Bruno Baudel. Qualquer dúvida, olhem o blog dos caras e deixem seus comentários.

4br4ç05,
nglauber

5 comentários:

Bruno disse...

Show de bola Glauber como sempre muito bem explicado seus topicos.

Anônimo disse...

NAO ESQUECER DE COLOCAR A PERMISSÃO NO ARQUIVO ANDROID MANIFEST!

Nelson Glauber de Vasconcelos Leal disse...

Oi Anônimo,

Obrigado por ter lembrado. Atualizei o post.

4br4ç05,
nglauber

rike disse...

Quando altera a orientação da tela o Progress desaparece...

Nelson Glauber de Vasconcelos Leal disse...

Oi rike,

Esse é um comportamento esperado...
Dá uma olhada nesse link
http://nglauber.blogspot.com.br/2012/08/cuide-da-sua-asynctask.html

4br4ç05,
nglauber