Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

Dúvida com progressDialog

Olá, estou com um pequeno problema para conseguir passar um Context para o progressDialog, sendo que o mesmo fica retornando nullexception como erro.

No meu mainactivity tenho um botão que no onclick chama uma classe chamada login, onde nesta classe é passado os dados do formulario para um outra classe global que eu criei para acessar meu webservice.

Nesta classe tenho o progressDialog, nomeado dentro de uma classe extendendo o AsyncTask:

@Override
protected void onPreExecute() {
    progressDialog = new ProgressDialog(getApplicationContext());
    progressDialog.setMessage("Carregando...");
    progressDialog.show();            
}

O que posso passar como parametro no new ProgressDialog? Seria o context da mainactivity?

Obrigado!

8 respostas

Oi Thiago,

isso mesmo, você pode passar o context da sua mainactivity. Para isso, basta criar um atributo nessa sua classe filha de AsyncTask.

Algo assim:

public class MinhaAsyncTask extends AsyncTask<...,...,...> {
    private Context ctx;

    public MinhaAsyncTask(Context ctx) {
        this.ctx = ctx;
    }

    @Override
    protected void onPreExecute() {
        progressDialog = new ProgressDialog(this.ctx);
        progressDialog.setMessage("Carregando...");
        progressDialog.show();            
    }

    //doInBackground e onPostExecute...
}

E na hora de chamar essa classe na sua mainactivity (que estou assumindo que seja uma Activity):

new MinhaAsyncTask(this);

Obrigado pela resposta Felipe!

Tentei e não rolou...

Vou tentar explicar melhor mostrando diretamente os codigos.

Na minha mainActivity, no método do onCreate eu chamo a minha classe login com os dados do form:

Button login = (Button) findViewById(R.id.btn_login);
login.setOnClickListener(new Login());

Já na classe de login eu instancio minha classe de conexão ao webservice (DBActivity) e chamo a função de iniciação:

DBActivity db = new DBActivity(dados, url);

String resposta = null;

try {
    resposta = db.initCon();
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (ExecutionException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

E finalmente, na classe de DBActivity, no método initPost() eu chamo a classe que extende o asynTask:

public class DBActivity extends MainActivity{

    protected String url;
    private Map<String, String> dados;
    private Context ctx;

    public DBActivity(Map<String, String> dados, String url) {

        this.dados = dados;
        this.url = url;
        this.ctx = ctx;

    }

    public String initCon() throws InterruptedException, ExecutionException {

        Log.i("PilatesOn", "instanciou o executor");
        String resposta = new initPost().execute().get();
        return resposta;
    }

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


        public ProgressDialog progressDialog;

        @Override
        protected void onPreExecute() {

            progressDialog = new ProgressDialog(ctx);
            progressDialog.setMessage("Carregando...");
            progressDialog.show();

        }

Como ficaria neste caso? Como eu poderia puxar o context da main em uma classe filha de uma classe que extende a main?

Se tiver qualquer sugestão de melhoria no codigo eu ouço com prazer, estou começando a trabalhar com android agora.

Obrigado!

Faltou postar o restante da classe initPost? Com todo o código, fica mais fácil propor alguma solução legal.

Oi Thiago, pode postar o log e o código do método onPostExecute?

Abs

Desculpe, postando agora:

@Override
    protected String doInBackground(String... params) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(url);

        Log.i("Filtro", "instanciou a DB");

        String responseContent = null;

        try {

            // Add your data
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();

            Set<String> chaves = dados.keySet();  

            for (Iterator<String> iterator = chaves.iterator(); iterator.hasNext();)  {  
                String chave = iterator.next();  
                if(chave != null) { 
                    nameValuePairs.add(new BasicNameValuePair(chave, dados.get(chave)));
                }
            }

            httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

            Log.i("Filtro", "Fez a requisição post");

            // Execute HTTP Post Request
            HttpResponse response = httpclient.execute(httppost);

            if (response != null) {

                InputStream in = response.getEntity().getContent();

                responseContent = inputStreamToString(in);

                Log.i("Filtro", "Resultado "+responseContent);

            }

        } catch (ClientProtocolException e) {
            e.printStackTrace();
            Log.i("Filtro", "Ciente exception: "+e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            Log.i("Filtro", "IOS exception: "+e.getMessage());
        }

        return responseContent;
    }

    @Override
    protected void onPostExecute(String result) {
        if (progressDialog != null) {
            progressDialog.dismiss();
        }
        // process the result
        super.onPostExecute(result);
    }

    private String inputStreamToString(InputStream is) throws IOException {
        String line = "";
        StringBuilder total = new StringBuilder();

        // Wrap a BufferedReader around the InputStream
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));

        // Read response until the end
        while ((line = rd.readLine()) != null) { 
            total.append(line); 
        }

        // Return full string
        return total.toString();
    }

}
solução!

Minha sugestão seria quebrar seu código em 3 classes diferentes, para não ficar tudo embolado e separar as responsabilidades de cada uma:

  • Uma Activity deve ser responsável somente por controlar a tela e exibir coisas nela e não precisamos alterar o seu construtor, pois não somos responsáveis por dar new nela. Quem cuida disso é o Android.

  • Uma AsyncTask deve cuidar somente de tarefas assíncronas (como acesso ao webservice, por exemplo)

Usando essas duas dicas, fiz isso aqui:

A sua classe DBActivity na realidade não gerencia nada da tela, ela cuida apenas da conexão com seu webservice. Então tirei a herança, deixei apenas a asynctask lá dentro e chamei de DBConector:

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


    private final Map<String, String> dados;
    private final String url;
    private final Context ctx;
    public ProgressDialog progressDialog;

    public DBConector(Map<String, String> dados, String url, Context ctx) {

        this.dados = dados;
        this.url = url;
        this.ctx = ctx;

    }

    public void executa() {
        Log.i("PilatesOn", "instanciou o executor");
        this.execute();
    }

    @Override
    protected void onPreExecute() {

        progressDialog = new ProgressDialog(ctx);
        progressDialog.setMessage("Carregando...");
        progressDialog.show();

    }

    @Override
    protected String doInBackground(String... params) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(url);

        Log.i("Filtro", "instanciou a DB");

        String responseContent = null;

        try {

            // Add your data
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();

            Set<String> chaves = dados.keySet();

            for (Iterator<String> iterator = chaves.iterator(); iterator.hasNext(); ) {
                String chave = iterator.next();
                if (chave != null) {
                    nameValuePairs.add(new BasicNameValuePair(chave, dados.get(chave)));
                }
            }

            httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

            Log.i("Filtro", "Fez a requisição post");

            // Execute HTTP Post Request
            HttpResponse response = httpclient.execute(httppost);

            if (response != null) {

                InputStream in = response.getEntity().getContent();

                responseContent = inputStreamToString(in);

                Log.i("Filtro", "Resultado " + responseContent);

            }

        } catch (ClientProtocolException e) {
            e.printStackTrace();
            Log.i("Filtro", "Ciente exception: " + e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            Log.i("Filtro", "IOS exception: " + e.getMessage());
        }

        return responseContent;
    }

    @Override
    protected void onPostExecute(String result) {
        if (progressDialog != null) {
            progressDialog.dismiss();
        }
        // process the result
        super.onPostExecute(result);
    }

    private String inputStreamToString(InputStream is) throws IOException {
        String line = "";
        StringBuilder total = new StringBuilder();

        // Wrap a BufferedReader around the InputStream
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));

        // Read response until the end
        while ((line = rd.readLine()) != null) {
            total.append(line);
        }

        // Return full string
        return total.toString();
    }
}

Como você tinha uma classe Login, mantive ela e fiz ela ser a responsável por instanciar esse DBConector:

public class Login implements View.OnClickListener {

    private final Map<String, String> dados;
    private final String url;
    private final Context ctx;

    public Login(Map<String, String> dados, String url, Context ctx) {
        this.dados = dados;
        this.url = url;
        this.ctx = ctx;
    }

    @Override
    public void onClick(View v) {

        DBConector db = new DBConector(dados, url, ctx);
        db.executa();
    }
}

E essa classe Login é chamada lá no clique do botão:

        Map<String, String> dados; //Você precisa passar isso aqui;
        String url; //Precisa popular essa variável também;

        Button login = (Button) findViewById(R.id.btn_login);
        login.setOnClickListener(new Login(dados, url, this));

Veja que o terceiro argumento do Login é o context.

Abraço.

Muito obrigado Felipe, exatamente isto que estava procurando, uma forma de trazer o context do main para a classe do async.

Uma dúvida, não seria melhor eu instanciar as variaveis de dados e url na classe de Login ao inves de fazer isso no OnCreate?

Sem problemas. Pode instanciar em qualquer um dos lugares.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software