Matheus Castiglioni

Consumindo Web Service No Android

Uma tarefa muito comúm do dia a dia seria realizar requisições HTTP e consumir Web Services, mas as vezes pode ser um tanto quanto chata pois precisa de configurações e alguns passos a serem seguidos.

Para exemplo do post, vamos consumir um serviço para buscas de CEP, os passos que deveriamos seguir são:

Após concluir todos esses passos teremos nossa app funcionando da seguinte maneira:

Exemplo consumir serviço de CEP

Desenhando nossa app

O primeiro passo será criar o layout da nossa app, como o assunto do post refere-se ao web service, irei disponibilizar o layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="50dp"
    android:layout_width="match_parent"
    tools:context="br.com.matheuscastiglioni.blog.requisicao_http.MainActivity">

    <EditText
        android:digits="0123456789"
        android:layout_height="wrap_content"
        android:hint="CEP"
        android:id="@+id/etMain_cep"
        android:textColor="#595959"
        android:textSize="25sp"
        android:inputType="number"
        android:layout_width="match_parent"/>

    <LinearLayout
        android:gravity="center"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_width="match_parent">

        <Button
            android:background="@color/colorPrimary"
            android:layout_height="wrap_content"
            android:id="@+id/btnMain_buscarCep"
            android:layout_marginBottom="10dp"
            android:padding="10dp"
            android:text="Buscar CEP"
            android:textColor="#FDFDFD"
            android:textSize="22sp"
            android:layout_width="wrap_content"/>

    </LinearLayout>

    <TextView
        android:layout_height="match_parent"
        android:id="@+id/etMain_resposta"
        android:textColor="#595959"
        android:textSize="20sp"
        android:layout_width="match_parent"/>

</LinearLayout>

Após adicionar esse layout para a activity, devemos ter nossa app parecido com:

App para consumir CEP

Consumindo um serviço

Agora que o layout esta pronto, podemos começar a consumir nosso serviço, para isso alguns passos devem ser seguidos, sendo eles:

Adicionando um listener no botão

Primeiro vamos começar adicionando um listener em nosso botão, para quando ele for clicado realizar alguma função, mas como podemos fazer isso ? Para trabalhar com eventos de click em botões podemos utilizar o setOnClickListener.

Vamos buscar nosso botão e atribuí-lo em uma variável:

Button btnBuscarCep = findViewById(R.id.btnMain_buscarCep);

Agora precisamos adicionar o listener no botão:

btnBuscarCep.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View view) {
		// buscar o CEP
	}
});

Pronto, com isso já devemos ser capazes de escutar e emitir alguma função quando o botão for clicado.

Criando a classe para buscar o CEP

Para realizar a busca do CEP vamos criar uma classe responsável por esse requisição HTTP:

public class HttpService {

}

Vou chamar a classe de HttpService pois a mesma irá consumir um serviço HTTP. Aqui entra um detalhe, toda requisição HTTP deve ser feita em background pelo Android, ou seja, a mesma não pode ser feita na thread principal, mas porque isso ocorre ?

Entendendo como uma requisição HTTP funciona

Uma requisição HTTP é feita da seguinte maneira:

Veja que no terceiro passo não sabemos quanto tempo o servidor irá levar para conseguir processar a requisição e devolver a resposta para a gente, por isso o Android exige que a requisição seja feita em background, assim o app não irá travar ou ficar congelado para o usuário enquanto a requisição é realizada.

Beleza Matheus, agora sabemos o motivo do Android exigir que a requisição seja feita em background ou em segundo plano, mas como podemos fazer isso ?

Adaptando nossa classe

O primeiro passo será extender a classe AsyncTask do Android responsável por realizar tarefas em background.

public class HttpService extends AsyncTask<Void, Void, CEP> {

}

Opa, espera ae Matheus, que doidera é essa de Void, Void, CEP ?

Parâmetros do AsyncTask

Calma, vamos devagar, para tudo tem uma explicação, sempre que extendemos a AsyncTask devemos passar esse três parâmetros para ela, sendo eles:

Criando o modelo CEP

Repare que o terceiro parâmetro da AsyncTask é uma classe CEP, mas ainda não temos ela, então vamos cria-la:

public class CEP {

    private String cep;
    private String logradouro;
    private String complemento;
    private String bairro;
    private String cidade;
    private String estado;

    public String getCep() {
        return cep;
    }

    public void setCep(String cep) {
        this.cep = cep;
    }

    public String getLogradouro() {
        return logradouro;
    }

    public void setLogradouro(String logradouro) {
        this.logradouro = logradouro;
    }

    public String getComplemento() {
        return complemento;
    }

    public void setComplemento(String complemento) {
        this.complemento = complemento;
    }

    public String getBairro() {
        return bairro;
    }

    public void setBairro(String bairro) {
        this.bairro = bairro;
    }

    public String getCidade() {
        return cidade;
    }

    public void setCidade(String cidade) {
        this.cidade = cidade;
    }

    public String getEstado() {
        return estado;
    }

    public void setEstado(String estado) {
        this.estado = estado;
    }

	@Override
    public String toString() {
        return "CEP: " + getCep()
                + "\nLogradouro: " + getLogradouro()
                + "\nComplemento: " + getComplemento()
                + "\nBairro: " + getBairro()
                + "\nCidade:" + getCidade()
                + "\nEstado: " + getEstado();
    }

}

Veja que trata apenas de uma classe para representar e armazenar as informações de nosso CEP, não tem segredo.

Bom, agora que já extendemos a classe AsyncTask e conseguimos entender seus parâmetros, devemos sobrescrever o método responsável pela execução em background:

Realizando a requisição em background

O único método que somos obrigados a sobrescrever quando extendemos de AsyncTask é o doInBackground, como o próprio nome já diz, será o método responsável por realizar a requisição para nosso web service em background.

@Override
protected CEP doInBackground(Void... voids) {
	// realizar requisição e consumir o serviço
}

Para realizar a requisição precisamos de um CEP, mas em nossa classe não recebemos ele ainda, como podemos resolver o problema ? Se nossa classe HttpService precisa de um CEP para funcionar, porque não passar o CEP pelo construtor ? Assim garantimos que sempre ela terá um CEP ao ser instânciada(usada):

private final String cep;

public HttpService(String cep) {
	this.cep = cep;
}

Veja que agora já possuímos um CEP para buscar os dados. O primeiro passo para nossa requisição funcionar será validar o CEP digitado e passado para nossa classe:

@Override
protected CEP doInBackground(Void... voids) {
	if (this.cep != null && this.cep.length() == 8) {
		// realizar busca
	}
}

Repare que agora estamos validando se foi passado um CEP e se o mesmo contém oito dígitos.

Configurando e realizando a requisição

Vamos começar a configurar nossa requisição, o primeiro passo é termos uma URL para consumirmos:

URL url = new URL("http://ws.matheuscastiglioni.com.br/ws/cep/find/" + this.cep + "/json/");

Durante a construção da URL pode acontecer de passarmos uma inválida ou que não existe, por isso, devemos realizar um tratamento de exceção com try catch:

try {
	URL url = new URL("http://ws.matheuscastiglioni.com.br/ws/cep/find/" + this.cep + "/json/");
	} catch (MalformedURLException e) {
		e.printStackTrace();
	}
}

Agora precisamos abrir uma conexão e configurar os cabeçalhos dela(Tipo de requisição, tipo de retorno, tempo máximo de espera, etc…):

try {
	URL url = new URL("http://ws.matheuscastiglioni.com.br/ws/cep/find/" + this.cep + "/json/");
	HttpURLConnection connection = (HttpURLConnection) url.openConnection();
	connection.setRequestMethod("GET");
	connection.setRequestProperty("Content-type", "application/json");
	connection.setRequestProperty("Accept", "application/json");
	connection.setDoOutput(true);
	connection.setConnectTimeout(5000);
	} catch (MalformedURLException e) {
		e.printStackTrace();
	}
}

Com as configurações realizadas, precisamos de fato, realizar a conexão, ou seja, conectar em nossa url:

connection.connect();

Pronto, ja conseguimos conectar, mas não basta conectar e realizar a requisição, precisamos de fato pegar a resposta e salvar em alguma variável, como podemos fazer isso ?

Lendo a resposta da requisição

Podemos ler a resposta facilmente com a classe Scanner do pacote java.io, ela abstrai bastante a complexidade de ler informações:

Scanner scanner = new Scanner();

Beleza, estamos criando nosso scanner mas de onde ele vai ler as informações ? Para isso temos o método openStream em nossa url:

Scanner scanner = new Scanner(url.openStream());

Como quase todas as classes do pacote java.io, devemos tratar a exceção para arquivos não encontrados, como já temos nosso try catch, precisamos apenas adicionar mais um catch em nosso try:

catch (IOException e) {
	e.printStackTrace();
}

Agora, com as exceções tratadas e nosso scanner recebendo as informações, já podemos realizar a leitura da resposta:

StringBuilder resposta = new StringBuilder();
// if omitido

Scanner scanner = new Scanner(url.openStream());
while (scanner.hasNext()) {
	resposta.append(scanner.next());
}

Beleza, tudo certo ? Errado, até o momento lemos a resposta e passamos para a classe StringBuilder, porém, lembra que o terceiro parâmetro de nosso AsyncTask era do tipo CEP ? Pois é, sendo assim precisaremos retornar um CEP em nosso método doInBackground, pois até agora temos um JSON lido dentro de uma String:

{"codibge":3530706,"codestado":35,"cep":"13845-373","logradouro":"Rua Caiapós","complemento":"","bairro":"Jardim Igaçaba","cidade":"Mogi Guaçu","estado":"SP"}

Afinal, como podemos pegar esse JSON, gravar dentro de uma String e converte-lo para a classe CEP ?

Convertendo dados do json

Realizar a conversão de dados em Java pode ser algo trabalhoso, sabendo isso, a Google lançou uma biblioteca chamada GSON, responsável em abstrair a complexidade na hora de converter dados relacionados com JSON, para começar a usa-la, devemos declarar a dependência em nosso build.gradle:

compile 'com.google.code.gson:gson:2.8.2'

Depois de adicionar a dependência, realize o sincronismo do Gradle.

Retornando um CEP

Com nosso GSON instalado, podemos converter nosso JSON para um objeto do tipo CEP da seguinte maneira:

return new Gson().fromJson(resposta.toString(), CEP.class);

Muito simples não ?

Agora que nossa classe responsável por realizar a requisição esta pronta, podemos utilizada em listener de nosso botão. Caso tenha se perdido em algum passo, segue a classe completa:

public class HttpService extends AsyncTask<Void, Void, CEP> {

    private final String cep;

    public HttpService(String cep) {
        this.cep = cep;
    }

    @Override
    protected CEP doInBackground(Void... voids) {
        StringBuilder resposta = new StringBuilder();

        if (this.cep != null && this.cep.length() == 8) {
            try {
                URL url = new URL("http://ws.matheuscastiglioni.com.br/ws/cep/find/" + this.cep + "/json/");

                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setRequestProperty("Content-type", "application/json");
                connection.setRequestProperty("Accept", "application/json");
                connection.setDoOutput(true);
                connection.setConnectTimeout(5000);
                connection.connect();

                Scanner scanner = new Scanner(url.openStream());
                while (scanner.hasNext()) {
                    resposta.append(scanner.next());
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return new Gson().fromJson(resposta.toString(), CEP.class);
    }
}

Retornando os dados para o usuário

Bom, até o momento de todos os passos que deveriamos realizar:

Ja concluímos os três primeiros, portanto, precisamos apenas retornar os dados para o usuário.

Buscando os dados do CEP

Vamos começar buscando os dados do CEP digitado em nosso app, para isso já haviamos criado o listener, precisamos apenas fazer uso da nossa classe HttpService:

final EditText cep = findViewById(R.id.etMain_cep);
final TextView resposta = findViewById(R.id.etMain_resposta);

Button btnBuscarCep = findViewById(R.id.btnMain_buscarCep);
btnBuscarCep.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View view) {
		try {
			CEP retorno = new HttpService(cep.getText().toString()).execute().get();
			resposta.setText(retorno.toString());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
});

Com isso iremos ter o seguinte resultado:

App em funcionamento

Caso tenha ficado alguma dúvida, você pode encontrar o projeto completo aqui, também gravei um vídeo no meu canal mostrando a parte prática da implementação:

Matheus Castiglioni

Matheus Castiglioni

Apaixonado pelo mundo dos códigos e um eterno estudante, gosto de aprender e saber um pouco de tudo, aquela curiosidade de saber como tudo funciona, tento compartilhar o máximo de conhecimentos adquiridos e ajudar todos aqueles que sou capaz.

comments powered by Disqus