16
respostas

Como receber dados do WebService???

Bom dia.

Estou trabalhando com uma activity que tem 2 fragments. Quando entro em um fragment, ele chama uma classe Async, que faz solicitação ao webservice e pega um json.

Preciso que esse json popule um spinner.

Onde devo inserir o código? No onPostExecute? No fragment? Podem me ajudar por favor?

Muito obrigado.

16 respostas

Olá Nicolas,

Isso mesmo, o local correto para disparar a atualização do seu spinner é o onPostExecute da AsyncTask que busca o JSON. Nesse ponto você pode atualizar qualquer componente da tela sem que o sistema operacional dispare uma exception. Como o spinner vai estar disponível somente dentro do seu fragment, o ideal é que você passe uma referência do fragment para a sua task e então invoque algum método do fragment para popular o spinner.

Entendi o sentido.

Mas não estou conseguindo aplicar isso. Poderia me dar uma ajuda ou então indicar algum material de estudo?

Obrigado.

Certo, vamos usar seu código como base. Poste aqui o código do seu fragment que contém o Spinner e também o código da classe que representa a sua AsyncTask.

Eu consegui fazer, mas não sei se é o recomendado, e ainda não consegui preencher o spinner com o json recebido. Eu fiz o seguinte:

No Fragment, eu criei o spinner e chamei a AsyncTask passando o context e a view.

 spinner = (Spinner) view.findViewById(R.id.intro_spin_selecionaEstado);

new BuscaEstadosTASK(getContext(), view).execute();

Na AsyncTask , método onPostExecute, eu tive que criar novamente o spinner e consegui fazer o spinner receber um array de testes, passado através de um array adapter:

String[] estados= {"Selecione seu estado...", "São Paulo", "Minas Gerais", "Rio de Janeiro"};

ArrayAdapter<String> adapterOpcoes = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, estados);

Spinner spinner = (Spinner) view.findViewById(R.id.intro_spin_selecionaEstado);
        spinner.setAdapter(adapterOpcoes);

Ele chegou a preencher o spinner corretamente, mas meu problema é que eu recebo um JSON do webservice, e precisava preencher o spinner com esse json:

{"estados":[{"id":"3","nome":"São Paulo"},{"id":"2","nome":"Minas Gerais"},{"id":"1","nome":"Rio de Janeiro"}]}

Como fazer para colocar esse json no spinner? E mais uma coisa, o acento que vem do json dá erro. Eu tenho que tratar isso no PHP ou no Android?

PS: Muito obrigado pela ajuda.

Olá Nicolas,

A forma de popular o Spinner não está incorreta, a única coisa que você tem que notar é que sua task acaba ficando acoplada demais a um fragment específico.

Para popular o seu spinner com o JSON, você vai precisar extrair os dados da String do JSON recebido. Para isso, você pode utilizar as classes JSONArray e JSONObject. A primeira coisa a fazer é transformar a String JSON em um JSONObject e isso é bem tranquilo de fazer bastando apenas passar a String no construtor do JSONObject:

String jsonDeResposta = // aqui vem a sua string JSON recebida
JSONObject json = new JSONObject(jsonDeResposta);

Ok, agora temos um objeto JSON mas dentro desse objeto temos uma lista de estados, ou melhor ainda, um JSONArray! Para extrair o JSONArray do nosso JSONObject, basta utilizar o método getJSONArray(...) especificando o nome da chave que representa o array no JSON:

JSONArray estados = json.getJSONArray("estados");

Agora precisamos pegar cada JSONObject dentro desse array e extrair o campo com a chave nome. Algo como no código abaixo:

for (int i = 0; i < estados.length(); i++) {
    JSONObject estado = estados.getJSONObject(i);
    String nomeDoEstado = estado.getString("nome");
    // aqui você adicionaria o estado lido no seu array que vai para o spinner
}

Na hora de implementar esse código, você vai precisar tratar a JSONException que pode ocorrer caso o JSON esteja com formato incorreto, por exemplo.

Tenta implementar e qualquer problema é só avisar.

Como eu faria então para nao deixar a Task presa a esse fragment?

Eu consigo retornar um valor para a fragment ao final do onPostExecute?? Tentei colocar um:

return respota;  //JSON RECEBIDO PELO WEBSERVICE

Mas não consigo receber nada no fragment.

Vou tentando popular o Spinner enquanto isso. rsrsrs

Olá Nicolas,

Ao invés de colocar o código de popular o spinner no onPostExecute suponha que você colocou esse código dentro de um método no seu Fragment:

public class FragmentComSpinner extends Fragment {
    private Spinner spinner;

    public View onCreateView(...) {
        // código normal do createview com inflate

        // depois do inflate, precisa pegar o spinner e guardar no atributo
        this.spinner = (Spinner) view.findViewById(R.id.intro_spin_selecionaEstado);
    }

    // outros métodos

    public void populaSpinner(List<String> estados) {
        ArrayAdapter<String> adapterOpcoes = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, estados);
        spinner.setAdapter(adapterOpcoes)        
    }
}

Agora, na sua AsyncTask, ao invés de receber uma View, você pode passar uma referência para o seu fragment e invocar dentro do onPostExecute(...) o método populaSpinner(...) passando os estados já extraídos do JSON.

Perceba que agora a responsabilidade de popular o spinner fica com o próprio fragment. A task só faz o requisição e extrai os dados da resposta e depois passa o resultado para o fragment invocando o método populaSpinner(...).

Eu consegui fazer o Fragment chamar a AsyncTASK, onde ela pega os dados do webservice e armazena em um JSON.

Apenas um detalhe, ao usar:

 ArrayAdapter<String> adapterOpcoes = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, estados);

O primeiro parâmetro como context não estava funcionando, então coloquei getContext(), que funcionou corretamente.

No método onPostExecute eu chamei o populaSpinner(), que também funcionou. (Usei um array simples de testes).

Ou seja, agora está quase tudo funcionando.

Só não consigo fazer ele pegar o JSON e popular o Spinner. Poderia dar uma olhada no código?

protected void onPostExecute(String resposta) {
        dialog.dismiss();
       try {
            JSONObject json = new JSONObject(resposta); //resposta é o JSON que veio do webservice através do:   String resposta = client.post();
            JSONArray estados = json.getJSONArray("estados");
            List<String> estadosArray = new ArrayList();

            for (int i = 0; i < estados.length(); i++) {
                JSONObject estado = estados.getJSONObject(i);
                String nomeDoEstado = estado.getString("nome");

                estadosArray.add(nomeDoEstado);
            }
            fragmentCom.populaSpinner(estadosArray);

        } catch (JSONException e) {
            e.printStackTrace();
            Toast.makeText(fragmentCom.getContext(), "Erro ao carregar spinner..", Toast.LENGTH_SHORT).show();
        }
}

E o populaSpinner() do Fragment está assim:

public void populaSpinner(List<String> estados) {
        ArrayAdapter<String> adapterOpcoes = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, estados);
        spinner.setAdapter(adapterOpcoes);
    }

O que pode ser o problema? Pois ele não está fazendo o que está dentro do try{}, vai direto ao catch.

Olá Nicolas!

Se ele está entrando no catch é porque aconteceu algum problema quando ele tentou parsear o JSON. Vamos ter que imprimir um log pra ver o que tá chegando de resposta do seu webservice.

Tenta colocar um Log.i("RESPOSTA", resposta); no começo do seu onPostExecute, roda o código novamente e depois checa no console qual o JSON que está chegando pra ver se tem algo estranho. Posta aqui depois pra gente ir tentando descobrir o que está errado.

Então, eu fiz o que você disse.

A resposta:

10-25 11:29:23.815 8264-8264/? I/RESPOSTA: {"estados":[{"id":"3","nome":"Minas
10-25 11:29:23.825 8264-8264/? W/System.err: org.json.JSONException: Unterminated string at character 35 of {"estados":[{"id":"3","nome":"Minas

Ele cortou após o espaço separando as palavras...

Olá Nicolas,

Acho que nesse caso o problema está no webservice. Dá uma verificada se no webservice ele tá enviando o JSON sem quebras de linha. Se estiver, tem que tratar a String pra retirar essas quebras antes de enviar a resposta.

Bom dia Jeferson, tudo certo?

Eu estava olhando, o código em php devolve o JSON em uma linha, sem quebras...

Quando ele pega um campo do banco de dados, com espaços em branco, por exemplo "São Paulo", ele dá erro no android e não executa.

Quando eu altero o campo para "São_Paulo", sem espaços em branco, ele carrega normalmente no spinner, executando as funções corretamente.

Tem alguma dica?

Olá Nicolas,

A classe Scanner do Java utiliza por padrão o caractere de espaço como delimitador para fazer a separação da String no momento da leitura. Isso significa que toda vez que invocamos o método next() no Scanner, ele vai ler a String até chegar no primeiro espaço em branco.

Para resolver o problema, vamos alterar o delimitador para a quebra de linha, o caractere \n.

Localize a sua classe que faz a requisiçao para o web service e que instancia o Scanner.

Vamos substituir a parte onde instanciamos o Scanner para:

Scanner scanner = new Scanner(connection.getInputStream()).useDelimiter("\n");

Faça essa alteração e teste novamente pra ver se resolve o problema!

Boa tarde Jeferson, tudo bem??

Fiz o que você falou, mas ele é um objeto Scanner, então eu criei uma String para receber esse Scanner.

Funcionou corretamente, só queria saber se o que eu coloquei depois seria uma boa prática realmente:

 Scanner jResposta = new Scanner(connection.getInputStream()).useDelimiter("\n");

 String respostaString = jResposta.next();
 return respostaString;

É correto fazer o que eu fiz aí em cima?

Opa, que bom que funcionou!

O que você fez faz sentido sim. Quando você invoca o método next() no Scanner ele devolve uma String que você pode devolver como resposta do seu método sem problemas.

Muito obrigado Jeferson por sua ajuda e presteza.

Agora está tudo funcionando corretamente. Faz uma solicitação ao webservice, preenchendo um spinner com a resposta, utilizando fragments (com Async TASK).

Muito obrigado, até mais.