AsyncTask – Executando tarefas em segundo plano.

Android AsyncTask

AsyncTask um Substituto de Threads e Handles

Como todo desenvolvedor Android sabe, é bem chato mexer com Threads, ainda mais quando há necessidade de atualizar a interface, para isso atualmente usamos a famosa ThreadUI ou Handler.

Pesquisando, encontrei uma maneira de trabalhar com essas Threads distintas facilmente utilizando a classe AsyncTask, com ela nos não precisamos nos preocupar com o tal de Handler. Nela executamos qualquer processo paralelamente e temos um método responsável por atualizar a interface.

Quando estendemos a AsyncTask ele nos obriga a definir três tipos de classes:

(defini esses tipos como exemplo)

extends AsyncTask<String, Object, Integer>

    1. O primeiro tipo ira definir o tipo que será passado para o método doInBackground(String… paramss), esses parâmetros vão ser passados ao executarmos o processo.
    2. O segundo tipo ira definir o tipo que será passado para o método onProgressUpdate(Object… values).
    3. O terceiro tipo ira definir o retorno do método doInBackground, assim que termina a execução do doInBackground esse tipo será retornado para o método onPostExecute(Integer… values).

Ao implementar uma classe que extend a AsyncTask podemos sobrescrever os seguintes métodos:

1 - onPreExecute.

É chamado antes de executar o processo (doInBackground), Podemos utilizar para criarmos um ProgressDialogo. Este método roda em Thread de interface.

2 - doInBackground

É responsável pelo processo. ex: uma busca em um webservice, algum download, qualquer processo que demanda tempo e processamento.

Não podemos utilizar este método para atualizarmos nossa interface, para isso temos a onProgressUpdate, MAS NÃO CHAMAREMOS ELA DIRETAMENTE para isso temos o método publishProgress que fica responsável por chamar a onProgressUpdate.

3 - onPostExecute

Este método recebera um parâmetro do doInBackground, ele é responsável em terminar a execução do processo, por exemplo finalizar um ProgressDialogo.

4 - onProgressUpdate

Este método é responsável em atualizar nossa interface. Chamamos ele atravéz do método publishProgress

Na pratica isso facilita e muito, acabando com os problemas de atualizar interface fora de um handler! mensagem de erro muito comum acredito!.

Segue um exemplo de como implementar um processo que demanda tempo, sempre atualizando a interface.

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        /** Chamando o Processo AsyncTask
         *  Os parametros passado no método execute, vão para o método
         *  doInBackground(Integer... params).
         */
        Processo processo = new Processo(this);
        processo.execute(3000, 2000, 4000);
    }

    public class Processo extends AsyncTask<Integer, String, Integer> {

        private ProgressDialog progress;
        private Context context;

        public Processo(Context context) {
            this.context = context;
        }

        @Override
        protected void onPreExecute() {
            //Cria novo um ProgressDialogo e exibe
            progress = new ProgressDialog(context);
            progress.setMessage("Aguarde...");
            progress.show();
        }

        @Override
        protected Integer doInBackground(Integer... paramss) {
            for (int i = 0; i < paramss.length; i++) {
                try {
                    //Simula processo...
                    Thread.sleep(paramss[i]);
                    //Atualiza a interface através do onProgressUpdate
                    publishProgress(i + "...");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return 1;
        }

        @Override
        protected void onPostExecute(Integer result) {
            //Cancela progressDialogo
            progress.dismiss();
        }

        @Override
        protected void onProgressUpdate(String... values) {
            //Atualiza mensagem
            progress.setMessage(values[0]);
        }
    }
}

Att.
Guilherme Biff Zarelli

Help DEV – Analista desenvolvedor Java / Android

http://helpdev.com.br/zarelli

44 thoughts on “AsyncTask – Executando tarefas em segundo plano.

      • Guilherme boa noite.

        Estou com um ‘problema’ e gostaria de sua ajuda. Estou desenvolvendo um agenda de tarefas e em cada registro tenho um horário para a execução da tarefa. Preciso criar uma classe q envie uma msg (SMS ou wapp) para o telefone da pessoa que fez o agendamento comigo, uma hora antes do horário marcado. Pensei em usar o AsyncTask mas dentro do método ele não permite que eu leia o BD para verificar o horário nos registros. O que vc sugere?

        Aguardo e já agradeço.

    • As reticências significa que você pode passar varios parametros do tipo declarado por exemplo:
      tenho o seguinte método:
      public void teste(String… parametros){…}

      Isso significa que parametros é um array de strings (String[]) os itens do array é igual a ordem que você passa.

      Posso chamar esse método das seguintes maneiras:
      teste(“1″,”2″,”3″,”4″,”5″);
      teste(“1″,”2″,”3″);
      teste();

      Posso ir adicionando varias strings na chamada, e como eu acesso os dados dentro do método? da seguinte maneira:

      public void teste(String… parametros){
      String s1 = parametros[0];
      String s2 = parametros[1];
      String s3 = parametros[2];
      }

      Lembre-se que você tem que saber quantos parametros você passa para não ter problemas.
      Uma dica é passar sempre na primeira possição a quantidade de itens.

  1. Primeiramente, parabéns pelo trabalho!
    Estou com um problema. Sempre que eu giro a tela ele parece parar o processo e acaba travando a aplicação se eu continuar girando.

    Estou usando esse mesmo exemplo que falou e pretendo implementar para consumir um webservice.

    O que posso fazer?!

        • Bom Michael o você deve dar um implement Parcelable na asyncTask. ai resolve seu problema, porem você deve ter o mesmo problema caso mude a orientação da tela.

          Quando a orientação da activity é recriada e lembra que você passa o context para a asynctask? esse context quando a tela gira não existe mais, é por isso que da o erro, pois o progressDialog que ussa o context vai dar seu dismiss em um contexto inexistente…
          Para resolver, em teoria, você não deve recriar a asyncTask e trabalhar com a mesma porem deve-se passar o novo context para ela!. é quase o mesmo problema da luz apagar.
          veja o codigo abaixo como resolvo os dois problemas:

          public class MainActivity extends Activity {
          
              private Processo processo;
          
              @Override
              public void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
          
                  /**
                   * Esse if/else serve para tratar a orientação.
                   */
                  if (savedInstanceState == null) {
                      processo = new Processo(this);
                      processo.execute(3000, 2000, 2000, 2000, 2000, 2000, 2000, 2000);
                  } else {
                      processo = (Processo) savedInstanceState.get("asyncTask");
                      processo.setContext(this);
                  }
          
                  setContentView(R.layout.main);
              }
          
              @Override
              protected void onSaveInstanceState(Bundle outState) {
                  //aqui eu salvo meu estado do processo
                  outState.putParcelable("asyncTask", processo);
                  super.onSaveInstanceState(outState);
              }
          
              public class Processo extends AsyncTask<Integer, String, Integer> implements Parcelable {
          
                  private ProgressDialog progress;
                  private Context context;
                  private String texto;
          
                  public Processo(Context context) {
                      this.context = context;
                  }
          
                  public void setContext(Context context) {
                      this.context = context;
                      showProgress(texto);
                  }
          
                  @Override
                  protected void onPreExecute() {
                      showProgress("Aguarde...");
                  }
          
                  private void showProgress(String texto) {
                      progress = new ProgressDialog(context);
                      progress.setMessage(texto);
                      progress.show();
                  }
          
                  @Override
                  protected Integer doInBackground(Integer... paramss) {
                      for (int i = 0; i < paramss.length; i++) {
                          try {
                              //Simula processo...
                              Thread.sleep(paramss[i]);
                              //Atualiza a interface através do onProgressUpdate
                              publishProgress(i + "...");
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                      }
                      return 1;
                  }
          
                  @Override
                  protected void onPostExecute(Integer result) {
                      //Cancela progressDialogo
                      progress.dismiss();
                  }
          
                  @Override
                  protected void onProgressUpdate(String... values) {
                      //Atualiza mensagem
                      texto = values[0];
                      progress.setMessage(texto);
                  }
          
                  public int describeContents() {
                      //estudar
                      return 0;
                  }
          
                  public void writeToParcel(Parcel arg0, int arg1) {
                      //estudar
                  }
              }
          }
          
    • Depende da onde esta dando o o que está gerando o erro, você deve analizar isso primeiro, insira codigos try catch:

      try{ 
      //codigo a ser tratado
      }catch(Exception ex){
      //tratamento da excessao
      }
      

      Passe o codigo para que eu possa analizar melhor se quiser abraço.

  2. Ola Guilherme,

    Gostaria de primeiro parabeniza-lo pelo excelente blog.

    E agora vai minha duvida;
    Seguindo esse modelo, estou consumindo um webservice com ele, porem, eu preciso chamar varios processos distintos, tais como; login, depois pegar lista de clientes e etc.

    Gostaria de saber como eu atualizo uma mesma progressDialog com varios asynctasks excecutados sequenciamente.

    Por Exemplo: Inicio metodo de login e atualizo o progressDialog para :”logando..”, depois para “Logado”. A partir dai preciso iniciar outro metodo para pegar os clientes, eu queria atualizar a mesma progressDialog para “Baixando clientes”.

    Como eu faria isso?

    • Olá Junior,
      Então, o esquema é você fazer na mesma async não tem jeito? você pode chamar o execute varias vezes, ai você passa parametros para ele dizendo “o que fazer” e trate dentro do doInBackground, assim você teria uma instancia do progress e atualizaria ele no onProgressUpdate…

      por exemplo:

      private ProgressDialog;
      
      onCreate(){
      //crio meu progress e exibo antes de dar o execute
      //async.execute(1);//login
      //processamento
      //async.execute(2);//lista usuarios
      }
      
      public class AsyncAtualizador extends AsyncTask {
      @Override
          protected Object doInBackground(Object... arg0) {
            int tipo = (Integer)arg0[0];
            if(tipo==1){
              //operacaologin
              publishProgress("mensagem");
            } else if(tipo==2){
              //operacao lista
              publishProgress("mensagem");
            }
          }
      
          @Override
          protected void onProgressUpdate(Object... values) {
             String mensagem = (String)values[0];
             progressDialog.setMensagem(mensagem);
          }
      
      }
      

      Fiz rápido, mais se precisar de mais ajuda é só falar. é uma ideia!

  3. Fala cara, beleza?

    Estou utilizando uma asynctask pra realizar um update na minha base conectando com um servidor web…

    Mas minha tela apaga depois de um tempo ferrando com tudo… você poderia me ajudar?

    Abraços

  4. Pingback: AsyncTask – Executando tarefas em segundo plano « Arthur Lehdermann

  5. cara, consegui fazer funcionar no meu android e no android do tester, maaaaaaaas no android do chefe continua apagando a tela… tem alguma forma de ‘bular’ esse esquema? pqp uhauhauha tô fritando neorônio já.. Obrigado por responder, você tem alguma comunidade que funcione? Todas as que eu encontrei, pelo menos aqui no Br. o pessoal demorou mais tempo que o projeto inteiro para responder…

    To mandando o código, caso ajude…
    private class DoInBackground extends AsyncTask
    implements Parcelable
    {
    private ProgressDialog dialog;
    private int oldOrientation;
    private Context contexto;

    public DoInBackground(){
    Aguarde();
    }

    protected void onPreExecute()
    {
    Aguarde();
    }

    public void Aguarde(){
    oldOrientation = getRequestedOrientation();
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
    dialog = ProgressDialog.show(Splash.this, pr.getAguarde(), pr.getRecebendoDadosFrase(), false, false);
    }

    protected Void doInBackground(Void… unused)
    {

    try {
    if(sinc.getNrAreas() > 0)
    sinc.GetAreas(dataDAO.getDate());

    if(sinc.getNrPaineis() > 0)
    sinc.GetPaineis(dataDAO.getDate());

    if(sinc.getNrEnsaios() > 0)
    sinc.GetEnsaios(dataDAO.getDate());

    if(sinc.getNrEquipamento() > 0)
    sinc.GetEquipamento(dataDAO.getDate());

    //TempoSplash();
    } catch (Exception e) {
    onCancel();
    }

    return null;
    }

    protected void onPostExecute(Void unused)
    {
    try {
    sinc.SetData(dataDAO.getDate());
    } catch (Exception e) {
    onCancel();
    }
    onCancel();
    }

    public void onCancel()
    {
    setRequestedOrientation(oldOrientation);
    dialog.dismiss();
    TempoSplash();
    cancel(true);
    }

    protected void onProgressUpdate(String… values) {
    //Atualiza mensagem
    //texto = values[0];
    //progress.setMessage(texto);
    }

    public int describeContents() {
    // TODO Auto-generated method stub
    return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
    // TODO Auto-generated method stub

    }
    }

  6. Oi Cara sou novo em android e gostaria de saber como eu faco pra conseguir criar um asyncTask para usar como login? na verdade eu consigo fazer meu aparelho logar mas quando o usuario colocar o login errado da um erro! to meio perdido nisso!

      • na verdade eu só consigo logar se o usuário digitar o login correto, senão ae sim vem o erro! estava tentando colocar um alertDialog no publish progress quando o usuário digitar o login incorreto! mas nao estava conseguindo! seria possível vc me ajudar??

        • Você deve implementar o AlertDialog no método “onProgressUpdate(Object… values)” e assim que der o erro no método “protected Object doInBackground(Object… paramss)” você chama o “publishProgress” que será responsavel por chamar o onProgressUpdate e exibir o AlertDialog… CAso você esteja fazendo isso e estiver dando erro, envie o erro para analizarmos… lembre-se de tratar as exceções no doInBackground com trycatch ;)

      • Boa Tarde Guilherme Biff, olha meu problema e esse! se tiver como vc me ajudar ficarei muito agradecido!!

        public class ProgressoVisualizarOs extends AsyncTask{

        private ProgressDialog progresso;
        private Context contexto;

        final EditText etLogin = (EditText)findViewById(R.id.etLogin);
        final EditText etSenha = (EditText)findViewById(R.id.etSenha);
        final EditText etVeiculo = (EditText)findViewById(R.id.etVeiculo);

        String resposta;

        public ProgressoVisualizarOs(Context contexto){
        this.contexto = contexto;

        }

        @Override
        protected void onPreExecute(){
        progresso = new ProgressDialog(contexto);
        progresso.setTitle(“Aguardando conexao”);
        progresso.setMessage(“Aguarde…”);
        progresso.show();
        }

        @Override
        protected Integer doInBackground(Integer… params) {

        try{

        String Url = “Minha Url”;
        ArrayList parametrosPost = new ArrayList();
        parametrosPost.add(new BasicNameValuePair(“login”, etLogin.getText().toString()));
        parametrosPost.add(new BasicNameValuePair(“senha”, etSenha.getText().toString()));
        parametrosPost.add(new BasicNameValuePair(“placa”, etVeiculo.getText().toString()));
        parametrosPost.add(new BasicNameValuePair(“id_projeto”, “100″));

        String respostaRetornada = null;

        respostaRetornada = ConecaoHttpClient.ExecutaHttpPost(Url, parametrosPost);
        resposta = respostaRetornada.toString();
        resposta = resposta.replaceAll(“\s+”, “”);
        if(resposta.equals(“erro”)){
        Se a minha resposta for igual a erro eu devo mostrar!
        Aqui eu preciso do alertDialog ou de um Toast mesmo!

        }
        }catch(Exception e){
        e.getMessage();
        }
        return null;
        }

        @Override
        public void onPostExecute(Integer result){
        progresso.dismiss();

        Intent iVisualizaOS = new Intent(MainActivity.this,ListView2.class);
        Bundle parametrosLogin = new Bundle();
        parametrosLogin.putString(“ID_veiculo”, resposta);
        //parametrosLogin.putString(“Login”, etLogin.getText().toString());
        //parametrosLogin.putString(“Senha”, etSenha.getText().toString());
        //parametrosLogin.putString(“Veiculo”, etVeiculo.getText().toString());
        iVisualizaOS.putExtras(parametrosLogin);
        startActivity(iVisualizaOS);
        }

        @Override
        public void onProgressUpdate(String… values){
        Pra ser Sincero não sei oque fazer nessa parte!!

        }

        }

        • Nunca declare esses atributos como finais
          final EditText etLogin = (EditText)findViewById(R.id.etLogin);
          final EditText etSenha = (EditText)findViewById(R.id.etSenha);
          final EditText etVeiculo = (EditText)findViewById(R.id.etVeiculo);

          E utilize um meétodo para carrega-los. No caso o onPreExecute.
          Exemplo:
          private EditText etLogin ;
          private EditText etSenha;
          private EditText etVeiculo ;

          @Override
          protected void onPreExecute(){
          etLogin = (EditText)context.findViewById(R.id.etLogin);
          etSenha = (EditText)context.findViewById(R.id.etSenha);
          etVeiculo = (EditText)context.findViewById(R.id.etVeiculo);

          progresso = new ProgressDialog(contexto);
          progresso.setTitle(“Aguardando conexao”);
          progresso.setMessage(“Aguarde…”);
          progresso.show();
          }

          o onProgressUpdate você deve utilizar para atualizar a tela igual descrito no post, confira novamente. No caso:
          [...]
          if(resposta.equals(“erro”)){
          publishProgress(“erro”);
          }
          [...]

          @Override
          public void onProgressUpdate(String… values){
          if(values[0].equals(“erro”)){
          //Exibir alertDialog ou Toast. (lembre-se de utilizar o context) ex:
          //Toast.makeToast(context,”teste,Toast.TEMPO).show();
          }
          }

          • Bom dia Guilherme Biff! Olha ele funcionou mostrou usuário e senha e veiculo invalido mas ele ainda continua indo para próxima activity e como eu não tenho nada pra enviar via Requisição Http a Tela fica em Branco! na verdade a resposta que eu recebo eu envio novamente e recebo um Json mas como nao tenho nada para mandar ele activity fica em branco!!

          • voce nao entendeu o ciclo de vida… tente estudar sobre isso.

            é so voce tratar o resultado no onPostExecute.

            No seu doInBackground quando DER CERTO de um ‘return 0; quando der errado de um ‘return null’.

            Ai no seu onPostExecute faça:

            @Override
            public void onPostExecute(Integer result){
            progresso.dismiss();
            if(result !=null){
            Intent iVisualizaOS = new Intent(MainActivity.this,ListView2.class);
            Bundle parametrosLogin = new Bundle();
            parametrosLogin.putString(“ID_veiculo”, resposta);
            //parametrosLogin.putString(“Login”, etLogin.getText().toString());
            //parametrosLogin.putString(“Senha”, etSenha.getText().toString());
            //parametrosLogin.putString(“Veiculo”, etVeiculo.getText().toString());
            iVisualizaOS.putExtras(parametrosLogin);
            startActivity(iVisualizaOS);
            }else{
            //falha
            }
            }

            voce pode tratar diferentes tipos de codigos tambem.

          • Blz! funcionou peco ate desculpa pela minha ignorância estou aprendendo ainda! mas um AsyncTask só pode ser usado uma vez ele no pode consultar novamente se o usuário digitar errado uma vez! E agora??

          • Provavelmente você deve estar ‘construindo’ a Async no onCreate ou em outro lugar.

            Realmente você não pode chamar o .execute() mais de uma vez, porém nada te impede de instancia-lo novamente e chamar o execute… no caso faça isso quando você clica no botão:

            onClick(){
            Async processo = new Async();
            processo.execute();
            }

          • The constructor MainActivity.ProgressoVisualizaOs() is undefined !! esse e o erro que da! eu nao estou instaciando ela no click do botao! acho q nao e possivel ele ser criado no onClick().

  7. Olá guilherme, gostei muito do tutorial mas ainda não testei hehe .. só queria saber de voce se eu poderia usar esse código para implementar em um sisteminha que vou fazer, o sistema consiste em enviar informações do GPS do cel para uma URL via post a cada 60 segundos, pra você, qual seria a melhor forma de fazer isso ?

    Agradeço desde já.
    Abraço

  8. Olá xará! :D Parabéns pelo tutorial, bem esclarecedor. Lá vai minha pergunta: No doInBackground(Object… params) é certo eu passar um array de EditText? Faço isso porque o método executa uma consulta no web service, retorna o objeto e eu já queria mostrar os dados nos edits (id, marca e modelo). Se essa não é a abordagem mais indicada, por favor aconselhe-me.

    Valeu e continue com o site que é mto bom!

    • Tudo bem xará rs!… Bom vamos lá!… De forma alguma passe um array de EditText em seu execute(); afinal, o doInBackGround só vai realizar o processamento (nada de atualizar interface lá), o correto é passar o Context que contem os EditText no construtor da async. Assim no doInBackgroundd você chama o método publishProgress(); passando a mensagem que queira atualizar e sobreescreve o onProgressUpdate para tratar a mensagem. Segue um exemplo:

               private Context context;
              //construtor
              public Processo(Context context) {
                  this.context = context;
              }
      
              @Override
              protected Integer doInBackground(Integer... paramss) {
                      try {
                          //Atualiza a interface através do onProgressUpdate
                          publishProgress(R.id.edit_1, "Mensagem edit 1");
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  return 1;
              }
      
              @Override
              protected void onProgressUpdate(Object... values) {
                 ((EditText) context.findViewById((Integer)values[0])).setText((String)values[1]);
              }

      Não sei se voce entendeu muito bem o conceito, mais é assim que se faz! se quiser passar o Array de EditText tudo bem, mas passe isso no construtor da async task não no doInBackground e lembre-se que se voce for atualizar algum edit, sempre chame o publishProgress

      Ou passe um os IDs do edittext no execute (Mas nunca os Objetos muito menos atualize-os lá)

  9. Guilherme, to precisando usar a async task para pegar html de uma pagina, estou usando o comando openstream(), porem esta retornando nulo (testado no java e estava funcionando) como faço para pegar um html de um site usando asynctask ?

  10. Guilherme,

    Excelente post, parabéns.

    Seguinte… na minha aplicação preciso enviar uma mensagem(4 bytes) a cada 1 segundo.
    Caso aconteça algum evento (itemClick por exemplo) preciso de parar de enviar.
    Dá pra fazer isso com AsyncTask? Se possível, tem algum exemplo ?
    Grato.

Deixe uma resposta

O seu endereço de email não será publicado Campos obrigatórios são marcados *

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>