AsyncTask – Executando tarefas em segundo plano.

Android AsyncTask

AsyncTask um Substituto de Threads e Handles

Mudamos, veja em: http://helpdev.com.br/2012/02/10/asynctask-executando-tarefas-em-segundo-plano/

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:

Mudamos, veja em: http://helpdev.com.br/2012/02/10/asynctask-executando-tarefas-em-segundo-plano/

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.

Mudamos, veja em: http://helpdev.com.br/2012/02/10/asynctask-executando-tarefas-em-segundo-plano/

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.

Mudamos, veja em: http://helpdev.com.br/2012/02/10/asynctask-executando-tarefas-em-segundo-plano/

Att.
Guilherme Biff Zarelli

Anúncios

36 comentários sobre “AsyncTask – Executando tarefas em segundo plano.

  1. cara, vc é foda mesmo. muito bom seu trabalho, te admiro e tal mas não consigo resistir: mecher é com x …. hahahahahaha
    parabéns pelo artigo.
    stay nerd!

  2. O que significa o “…” reticências na declaração do argumento na linha 40?

    • 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.

  3. Muito bom, utilizar Threads e Handles é muito chato.
    Bem melhor dessa maneira!

  4. 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 dia, Obrigado Neemias, bom cara nesse caso para você tratar com a orientação da tela você deve usar o onSaveInstanceState e salvar a instancia de sua async task porem quando você retorna a instancia você deve falar para sua async quem é sua nova Activity, fiz um pequeno exemplo baixe nesse link: https://dl.dropbox.com/u/15643399/testeAsyncOrientacao.zip

      • Quando a luz da tela é apagada, da um erro dizendo que a classe MainActivity não é serializável.

      • 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
                }
            }
        }
        
  5. Boa noite Guilherme,
    Sabe me dizer como que eu faço para tratar um exception no momento em que o progressdialog esta em execução ?
    Desde já, obrigado.

    • 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.

  6. 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!

  7. 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

  8. Agora que vi o código acima uhauhauhauha vou tentar implementar!!

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

  10. 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

    }
    }

  11. 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!

    • Tudo bem ? seguindo este post você consegue implementar sem erros uma tela de login. Posso te ajudar se você dizer o erro que está ocorrendo.

      • 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().

  12. 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

  13. Como que eu faço para que em minha aplicação nunca tenha tela dormente ( a tela apaga depois de um tempo), quero que essa função sege superior a que vem no cel que é de preferência do usuario.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

w

Conectando a %s