Alura > Cursos de Mobile > Cursos de Android > Conteúdos de Android > Primeiras aulas do curso Android: acessando uma API Web

Android: acessando uma API Web

Entendendo o problema da persistência interna - Introdução

Olá, eu sou Alex Felipe, instrutor da Alura, e apresentarei a vocês o curso de Persistência Web em Android. Nosso objetivo será resolver um problema relatado por um cliente. Ele possui um aplicativo de estoque de produtos, com CRUD, envolvendo listagem, inserção, remoção, edição, comportamentos bem comuns. No entanto, em algumas situações as informações cadastradas são perdidas, e não há como recuperá-las.

Entenderemos que estes problemas ocorrem quando fazemos apenas a persistência interna, ou seja, quando trabalhamos com o Room, ou com banco de dados interno. Nestes casos corremos riscos, e é justamente isso que começaremos a resolver em nosso projeto. Temos produtos como computador, mesa, teclado, mouse e afins.

Se limparmos os dados contidos em nosso aplicativo ou o desinstalarmos, as informações armazenadas nele serão realmente perdidas. Como é que a persistência web dará conta disso? Isso será resolvido estabelecendo-se uma comunicação com uma API Web, cujo funcionamento veremos durante o curso.

Percebam que, se limparmos os dados do aplicativo em modo avião, perdemos tudo o que estava armazenado, mas com o wifi ativado, podemos fechar e reabrir o aplicativo, e as informações são recuperadas por conta da comunicação com a API Web. Aprenderemos a fazer esta integração, isto é, trabalhar com a persistência interna integrando-a à API Web.

Faremos isto justamente para evitar a insatisfação do nosso cliente. Em se tratando da parte mais técnica, do que acabaremos vendo e implementando, estão as requisições web via HTTP. Conheceremos algumas bibliotecas, veremos peculiaridades existentes durante este tipo de implementação, uma vez que já aprendemos a usar AsyncTask para realizar operações paralelas que tendem a demorar.

Da mesma forma, trabalharemos de forma a aprender a solucionar problemas com requisições web. Teremos muitos códigos complexos, este será um curso mais avançado, que exige mais pré-requisitos. Conto com a sua presença, espero que esteja animado para o curso, e vamos começar!

Entendendo o problema da persistência interna - Introdução ao projeto

Como primeiro passo, entenderemos a implementação do projeto, que desconhecemos até então. Como já foi comentado, trata-se de um CRUD de produtos, um aplicativo capaz de listar produtos, fazer inserções, remoções e edições. Vamos começar analisando o código de ListaProdutosActivity.java, a partir de uma simulação do que está acontecendo conforme o que está sendo exibido na tela.

Na tela com o texto "Lista de produtos", basicamente carregamos uma lista vazia, feita a partir do RecyclerView, um componente com comportamento similar à nossa ListView. Se acessarmos o método configuraListaProdutos(), percebemos que utilizamos o RecyclerView, configuramos seu Adapter, que é específico, diferente do AdapterView, e fazemos todas as configurações de lista a partir de ListaProdutosAdapter().

Caso você nunca tenha visto esta API, a recomendação é de que se faça o curso da Alura; durante este curso, o conhecimento de implementação do RecyclerView não é necessário, pois abstraí o máximo possível para que pudéssemos utilizá-lo como se fosse um Adapter do nosso ListView. Sendo assim, teremos apenas alguns métodos públicos, e não precisaremos nos preocupar muito com a implementação.

Na tela do aplicativo, existe um Floating Action Button que, ao ser clicado, em vez de abrir uma nova Activity, ele abre um dialog um pouco diferente do que já vimos, com Views, como é o caso de EditTexts, de componentes do Material Design. Neste caso em específico, são componentes chamados de TextInputLayout.

Durante cursos anteriores, iniciais principalmente, não vemos muito sobre esse assunto, existe um curso sobre validações de formulário aqui na plataforma em que acabamos vendo tudo isso um pouco mais. Não é o objetivo entender sobre estas peculiaridades, apenas escolhi estes componentes para um melhor aspecto visual.

Neste caso estamos usando um dialog personalizado e, se repararmos em ListaProdutosActivity.java, o Floating Action Button configuraFabSalvaProduto() faz setOnClickListener(), e chama abreFormularioSalvaProduto(). Mas quando fazemos isso, estamos basicamente criando o dialog SalvaProdutoDialog(), e se usarmos o atalho "Ctrl + B", ele faz a extensão de FormularioProdutoDialog enviando TITULO e TITULO_BOTAO_POSITIVO.

Porém, toda a implementação genérica o bastante para a sua reutilização no comportamento de edição se encontra em FormularioProdutoDialog. E para podermos usá-lo, precisamos de contexto, os dois títulos, e o listener, que já vai para o construtor do nosso FormularioProdutoDialog, seria então a representação abstrata e genérica para todo tipo de formulário que formos utilizar para lidar com dialogs.

Se acessarmos sua implementação, teremos todas as suas configurações e complexidades; o conhecimento sobre esta implementação não é obrigatório, caso haja curiosidade e quiser editar um pouco o código, fique à vontade. O foco, no entanto, é enviar o listener para indicar que um determinado produto foi finalizado, salvo ou editado.

E a configuração da parte visual é feita em mostra(), método que exibe o dialog, em que criamos uma View com viewCriada a partir de um XML de layout que criamos, formulario_produto, por exemplo. Usando o "Ctrl + B" nele, teremos toda a implementação feita para o formulário, com TextInputLayout, e tudo o mais.

Quando finalizamos a operação, usamos o listener para enviar o dado para quem chamou o dialog, no caso, quandoConfirmado(), em que mandamos produto. Isso fica acessível para quem chama os dialogs, então quando chamamos a instância do SalvaProdutoDialog() usamos uma expressão lambda, this::salva para a implementação do Listener de confirmação, que é justamente aquele que serve para todos os formulários a serem abertos via dialog, utilizando o formulário genérico que vimos.

Isso quer dizer que se tentamos editar um produto, reutilizamos o código de formulário. A diferença é que, se acessamos abreFormularioEditaProduto(), usamos EditaProdutoDialog(), que altera o título do dialog e do botão. Ou seja, FormularioProdutoDialog contém toda a lógica para a distinção do que será apresentado durante a edição ou inserção de um produto.

Ao acessarmos tentaPreencherFormulario(), é verificado se um produto existe no momento de instância do nosso formulário; caso exista, os campos serão preenchidos, e é exibido o ID. Vejam que é realmente uma implementação genérica a ser compartilhada entre os dois formulários. Assim, apesar de EditaProdutoDialog.java e SalvaProdutoDialog.java estarem bem simples, toda a complexidade se encontra em FormularioProdutoDialog.java.

Em abreFormularioEditaProduto() chamamos o método edita(), e no comportamento de salvar, salva, que são operações feitas em bancos de dados de forma assíncrona, assim como vimos no segundo curso de Room. Isso é necessário para não travar a Thread principal, nem a tela do usuário.

Em salva() criamos uma solução na qual utilizamos uma Async Task genérica, nomeada de BaseAsyncTask, cuja implementação usa Generics do Java. Desta forma não precisamos criar várias Async Tasks para cada operação; podemos reutilizar uma única delas incluindo o comportamento que queremos que seja executado no doInBackground() de executaListener, e depois que tudo é finalizado, no onPostExecute(), a partir de FinalizadaListener.

Assim, em ListaProdutosActivity.java, temos BaseAsyncTask e, na primeira expressão lambda indicamos que salvaremos um produto ao qual teremos acesso a partir de seu ID, que buscamos e retornamos, e que vai à outra expressão lambda, referente a FinalizadaListener, que por sua vez recebe o tipo genérico gerado.

Então, toda vez que colocarmos um comportamento em executaListener, é necessário devolver um valor com base no Generics atribuído, neste caso isto acontece com o produto, que queremos que esteja acessível após ser salvo. Depois disso, o incluímos no adapter, e toda a configuração que já vimos no Adapter View. Por fim, ele é executado, com execute().

No caso da edição do Adapter, em edita(), temos comportamento similar — a única diferença é que colocamos mais informações, como é o caso de posicao. Além de devolvermos um produto, então, que seja acessível em FinalizadaListener, também enviamos posicao. Toda a edição feita no banco de dados ocorre em background, numa Thread separada. O que é feito na Thread de UI é incluído em outro Listener.

O BaseAsyncTask é utilizado também para remoção e listagem, sendo este o mais simples de todos, porque não envolve tantas operações, uma vez que utilizamos method reference, a chamada mais enxuta em expressões lambdas.

Estes são os pontos principais, mas repito que se quiserem explorar o projeto, fiquem à vontade, todos os pacotes estão acessíveis, todo o código de implementação, como dito anteriormente, os conhecimentos em relação ao Converter são necessários, portanto é recomendado que se faça o segundo curso de Room.

Caso surjam dúvidas, entre em contato conosco via fórum.

Entendendo o problema da persistência interna - Entendendo a persistência externa

Agora que vimos como nosso projeto funciona, precisamos entender o motivo da perda de dados. O primeiro destaque a que atentaremos é que a solução que estamos utilizando para a persistência de dados é o Room, cuja técnica é interna.

Persistência de dados externa no Android

Dentre os problemas comuns na persistência interna, os quais acabam comprometendo os nossos dados, estão:

Como podemos evitar esses problemas?

Precisamos de uma solução que implique em uma flexibilidade capaz de, mesmo quando houver as ações acima, acessarmos os dados. Para isso, consideramos a persistência web, o mais famoso tipo de persistência externa. Se você já ouviu falar sobre soluções em cloud, a computação em nuvem, que lidam com servidores, esta é uma abordagem a ser considerada para evitar a perda de dados.

Assim, manteríamos todos os dados salvos internamente, portanto não necessariamente precisamos descartar a solução aplicada anteriormente, inclusive, isso é muito comum. Porém, em vez de salvarmos apenas internamente, estabeleceríamos uma comunicação externa com uma API, servidor, ou web service.

Ao enviarmos estes dados, fazemos uma espécie de backup para estes serviços online, os quais acabam se responsabilizando em mantê-los disponíveis para os nossos aplicativos. A ideia, então, é proteger os dados, garantindo sua integridade caso algo aconteça com eles localmente.

Vantagens da persistência web

Desvantagens da persistência web

A seguir veremos como utilizar esta API externa, e fazer a sua integração com o nosso aplicativo.

Sobre o curso Android: acessando uma API Web

O curso Android: acessando uma API Web possui 216 minutos de vídeos, em um total de 58 atividades. Gostou? Conheça nossos outros cursos de Android em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Android acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas