Consumindo APIs em Android com Retrofit e Butter Knife - Parte 2

Android SDK

Consumindo APIs em Android com Retrofit e Butter Knife - Parte 2

Luiz Duarte
Escrito por Luiz Duarte em 15/08/2017
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Esta é a segunda parte do tutorial de como consumir APIs em um app Android usando Retrofit e ButterKnife. Caso tenha caído aqui de pára-quedas, sugiro ler (e programar) a primeira parte do tutorial primeiro, seja clicando no link anterior ou usando o sumário logo abaixo (os itens 1 a 3 são da parte 1 do tutorial).

Apenas recapitulando, estou usando uma API escrita em Node.js com banco MySQL, cujo tutorial e fontes se encontram neste post. Esta API e seu banco estão hospedados na Umbler, que fornece MySQL gratuito para pequenos projetos.

Sobre as bibliotecas-foco desse tutorial, a Retrofit permite abstrair requisições HTTP a APIs usando classes Java de uma maneira muito elegante e produtiva. Enquanto o Butter Knife permite fazer o binding de recursos do seu app (componentes visuais, imagens, cores, strings, eventos, etc) com muito menos código do que normalmente é necessário.

E pra encerrar a introdução, a belíssima tela (#sqn) do nosso app está como abaixo:

Tela do app

Dito isso, veremos neste tutorial completo os seguintes itens (do 1 ao 3 já foram vistos na parte 1):

  1. Preparando a API
  2. Criando o app
  3. Usando ButterKnife
  4. Usando Retrofit
  5. Fazendo tudo funcionar
  6. Indo além!

Vamos lá!

#4 – Usando Retrofit

Como mencionado anteriormente, Retrofit é um HTTPClient que agiliza bastante algumas tarefas tediosas de mapear APIs HTTP em objetos Java para tornar as requisições mais type-safe.

Neste tutorial, temos uma API REST de clientes que possui algumas operações elementares que precisamos mapear para métodos e classes Java, o que o Retrofit vai nos permitir fazer muito facilmente. Mas antes de sair usando ele, precisamos adicioná-lo como uma dependência em nosso build.gradle (no Module: app), na seção dependencies (tal qual fizemos com o ButterKnife):

Aqui, eu adicionei o Retrofit e o converter que vai nos permitir serializar e desserializar JSON usando a biblioteca Gson (isso porque minha API trabalha com JSON, isso pode variar no seu caso). Apenas atente que o converter utilizado deve ser da mesma versão do seu Retrofit (2.3.0 no meu caso).

E no arquivo proguard-rules.pro, onde tem as configurações do Proguard, adicione as seguintes linhas (recomendação do dev do projeto Retrofit):

Atenção: se você não sabe o que é o Proguard, ele é um otimizador, minificador, ofuscador e pré-verificador de código Java que roda automaticamente segundo uma série de regras para tornar o APK final o menor possível (no caso do Android) e o mais “seguro” possível, do ponto de vista de ofuscação de código. Mais informações nesta resposta do Quora.

Com isso temos o Retrofit configurado em nosso projeto e pronto para usar. O primeiro passo é adicionar uma classe Java que representa um cliente do seu banco de dados, o que eu fiz abaixo do jeito mais simples possível:

Atenção: foi usada aqui a mesma capitalização (maiúsculas e minúsculas) das colunas da tabela Clientes do meu banco de dados MySQL. Ajuste de acordo com o seu cenário. Caso os nomes não coincidam, a desserialização não acontecerá corretamente mais tarde e os métodos retornarão clientes “vazios”.

Agora, adicione uma interface Java ao nosso projeto, que representará a API localmente. Aqui eu chamei de ClientesService.java:

Para cada endpoint da nossa API (falei sobre isso na parte 1 deste tutorial, lembra?), criamos um método na interface usando annotations para os verbos HTTP e para os parâmetros que devam vir no path e no body da requisição HTTP.

Para quem entende um mínimo de web APIs, o código é auto-explicativo.

Atenção: meu método que retorna cliente por id está retornando uma lista de clientes propositalmente porque na minha API Node+MySQL eu sempre retorno um array JSON em GETs. Outro ponto de atenção são os métodos de insert e update que possuem a annotation @FormUrlEncoded pois minha API Node+MySQL espera chave-valor no body (caso esperasse JSON, eu usaria um @Body Cliente como parâmetro). Métodos com esta annotation devem possuir parâmetros com @Field indicando o nome de cada chave que será enviada no body. Para saber os fields corretos, consulte a documentação da API (no meu caso, consulte o tutorial original).

Agora, para podermos usar esta interface, vamos adicionar uma nova variável e um método de carregamento dessa variável em nossa MainActivity.java:

Esse método de carregamento deve ter sua baseUrl apontada para a sua URL (no meu caso, node.luiztools.com.br). Caso queira apontar para uma webapi rodando localhost, use 10.0.2.2 como URL (e inclua a porta, se necessário). Além disso, esse método usa a biblioteca Gson para converter o body das requisições para JSON, conforme exigido pela minha API (isso pode variar na sua).

E no onCreate da MainActivity, adicione uma chamada à esse método logo no final (aproveitei para adicionar a permissão de uso de rede na thread principal, conforme explico melhor aqui):

Com isso, sempre que precisarmos consumir nosso webservice, basta chamar MainActivity.api.nomeDoMetodo e é isso que temos de fazer agora, substituindo aqueles testes fake por chamadas de verdade à API.

Atenção: como usaremos webapis através da Internet do smartphone, devemos ter permissão para tanto. Adiciona no AndroidManifest.xml as duas linhas logo no início, dentro da tag manifest:

Isso resolve para smartphones com Android anterior ao 6. Para smartphones Marshmallow (6) em diante, você deverá incluir um código de verificação e solicitação de permissão do usuário a cada requisição. Eu incluirei esse código nas chamadas dos métodos abaixo, então não se preocupe.

Curso React Native

#5 – Fazendo tudo funcionar

Agora que temos tudo pronto com nosso Retrofit, é hora de usar nosso recém-criado ClientesService através da variável api nos métodos de click dos nosso botões.

Vamos começar com o btnBuscarOnClick, que agora deverá ficar assim:

Note que houve uma imensa alteração aqui. Logo no início eu defino uma constante que define o número 1 para uma ação de busca, isso vai ser útil na sequência. Antes de fazer qualquer coisa no clique deste botão eu verifico se o app tem permissão de usar a Internet, caso contrário, solicita ao usuário que dê a referida permissão, passando o código desta ação de busca (1).

Caso ele tenha a permissão, o código flui naturalmente, usando o método da interface que retorna apenas um cliente por id e usando o cliente retornado para popular os campos.

Para que isto funcione, temos de sobrescrever o método onRequestPermissionsResult que é executado automaticamente após a permissão ter sido concedida ou não pelo usuário:

Aqui é onde usamos o código da ação de busca (1), pois todos os pedidos de permissão vão cair aqui e precisamos saber qual método executar após a permissão ser concedida. Essa permissão será requisitada apenas na primeira ação, nas subsequentes o fluxo cairá no else do código anterior a este e tudo acontecerá naturalmente pois a permissão fica salva.

Sugiro já realizar um teste aqui, para garantir que está funcionando. Acesse a API Node+MySQL no seu navegador e mande listar todos os clientes para pegar o ID de algum deles e usar no app para buscar.

Próximo passo, btnExcluirOnClick!

Aqui as mudanças não foram tão drásticas se você considerar que muita coisa é repetida em relação às permissões e à própria chamada da api em si, que é apenas um método pois o Retrofit faz todo o trabalho pela gente.

Note que defini uma nova constante para ACTION_EXCLUIR, constante essa que devemos incluir no switch/case do onRequestPermissionsResult:

Próximo passo, btnSalvarOnClick!

Neste método, que guarda muitas semelhanças com os anteriores, executamos o método correto da interface conforme for um insert ou update, no mais não há novidade alguma.

Não esqueça de incluir a nova constante ACTION_SALVAR no onRequestPermissionsResult:

Quando for testar o botão de salvar você receberá as mensagens de sucesso ou de fracasso, mas para ter certeza de que realmente funcionou, acesse sua API para ver se o cliente em questão foi alterado ou se apareceu um novo cliente, dependendo do seu caso.

#6 – Indo além!

Opcionalmente existem diversas melhorias que você pode fazer neste app.

Alguns apps usam o banco local (SQLite) para fazer cache dos dados da API que o app consome. Você aprende a usar o banco local neste post. Isso pode ser uma boa ideia dependendo do seu caso, apenas tomando cuidado de ter uma forma de atualizar o seu cache ou mesmo expirá-lo automaticamente.

Não criamos uma tela de listagem de todos os clientes neste tutorial. Isso geralmente é feito e a recomendação atual é usar RecyclerView para isto, um componente moderno e poderoso que permite criar belas e rápidas listagens. Neste post eu ensino como tirar um bom proveito do RecyclerView e com poucas adaptações você consegue usar neste tutorial aqui.

Não adicionei validações no formulário de cadastro/edição de cliente. Isso é super importante para garantir que somente dados íntegros sejam enviados à API. Facilmente você nota que se clicar diretamente em Salvar, sem preencher nenhum campo, mesmo assim um novo cliente vazio é cadastrado com um novo id.

Caso a API possuísse autenticação (a minha é aberta), existem algumas configurações adicionais no Retrofit para que ele envie junto o cabeçalho Authorization. Isso é melhor explicado na seção de Header Manipulation da documentação do Retrofit.

E com isso encerramos este tutorial de como consumir APIs em Android usando Retrofit e ButterKnife.

Espero que tenha gostado e que lhe seja útil!

Curso Beholder

TAGS:

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

2 Replies to “Consumindo APIs em Android com Retrofit e Butter Knife – Parte 2”

Ave Nasci

show de bola!
Uma duvida. Como faria para o servidor notificar o app de uma atualização em um registro no bando de dados ?

Luiz Fernando Jr

Dá pra fazer com Socket.io, conforme mostrei em um tutorial recente aqui no blog e que hoje deve sair a segunda parte usando Android. Acho que dá pra fazer com Firebase também.