Tutorial: CRUD em Android com SQLite e RecyclerView (Parte 2)

Seguimos agora com a tão aguardada segunda parte do Tutorial: CRUD em Android com SQLite e RecyclerView. Se chegou agora e ainda não fez a primeira parte do tutorial, faça, pois é bem difícil de conseguir acompanhar sem ter concluído todos os preparativos iniciais.

O que é uma RecyclerView? A RecyclerView é a substituta mais moderna ao ListView, que até então era o componente recomendado para criar listagens. No entanto, o ListView está atrelado à versão do SDK que você está rodando, é pesado e tem pouca flexibilidade. A RecyclerView é um pouco mais complicada de lidar mas vale a pena considerando os benefícios que se tem com ela, como veremos nesta segunda parte do tutorial.

Veremos neste tutorial:

  1. Criando e explorando o projeto Basic (parte 1)
  2. Criando a tela de cadastro/edição (parte 1)
  3. Preparando a persistência de dados (parte 1)
  4. Cadastrando Clientes (parte 1)
  5. Listando Clientes
  6. Atualizando Clientes
  7. Removendo Clientes

Mãos à obra!

Parte 5: Listando clientes

Primeiro, vamos criar na nossa classe ClienteDAO o método que vai retornar todos os clientes do banco de dados, como segue:

Aqui usamos o método rawQuery do objeto SQLiteDatabase para executar uma consulta SELECT em cima de todos clientes da base o que nos retorna um cursor. Com um laço em cima do curso conseguimos retornar cada uma das colunas em cada uma das linhas da tabela, populando uma coleção de Clientes com essas informações.

Atenção: para pegar o índice da coluna a partir do seu nome, o mesmo deve ser informado tal qual foi criado no CREATE TABLE original. Caso não queira pegar por nome, você pode pegar por índice, desde que saiba a ordem que as colunas serão retornadas do banco (se especificar as colunas ao invés de usar SELECT *, fica mais fácil).

Agora vamos voltar a nossa atenção ao arquivo de layout content_main.xml, que vamos editar para incluir uma lista de elementos nele, que mais tarde será populada com os clientes do banco de dados. Já que estamos usando de boas práticas em vários cantos, não usaremos aqui ListView, mas sim a versão mais moderna para listagem de elementos que é a RecyclerView, um componente gráfico independente de versão do SDK que é atualizado constantemente, tem muito mais desempenho, mas opções visuais e de animação, etc.

Para poder usar a RecyclerView, primeiro você deve adicionar algumas dependências no seu arquivo build.gradle dentro da pasta app, dentro da seção dependencies do mesmo:

Atenção: Certifique-se de que a versão das bibliotecas ‘-v7’ seja a mesma entre todos eles, no meu caso, 25.3.1, a mais recente na data que escrevo este post. É possível também que a dependência da biblioteca support:design já esteja adicionada nesse arquivo, nesse caso não precisa adicionar de novo.

Para podermos criar belas listas usando RecyclerView, devemos adotar uma técnica semelhante ao que fizemos no post sobre ListViews personalizadas: temos de ter um layout XML que represente um único item da lista, para o mesmo ser replicado.

Sendo assim, adicione um novo layout XML na pasta de layouts chamado item_lista.xml com o layout ConstraintLayout na raiz e crie uma interface semelhante à esta:

Item da Lista
Item da Lista

O código XML para fazer esta interface está abaixo. Você não precisa fazer igual, mas atente aos ids dos componentes que é o mais importante no momento:

Agora sim, vamos para a content_main.xml, apagamos aquele Hello World que estava lá e vamos adicionar uma RecyclerView, que fica na categoria AppCompat da Palette do Layout Editor do Android Studio.

A RecyclerView possui uma propriedade listitem, onde devemos informar o layout XML que usaremos para os itens da mesma, no nosso caso, o item_lista.xml:

O preview da sua tela principal deve mudar também, logo após você adicionar a informação do layout da lista.

Para que os campos do item_lista.xml sejam mapeados corretamente quando carregarmos os elementos na lista, devemos criar uma classe Java extendendo ViewHolder, como a ClienteHolder.java abaixo:

Na sequência, vamos criar o ClienteAdapter.java que vai fazer a ligação entre os dados dos clientes e os campos do layout item_lista. Para a classe ser uma Adapter é necessário herdar RecyclerView.Adapter<ViewHolder> e implementar os métodos obrigatórios.

  • onCreateViewHolder(ViewGroup parent, int viewType): Método que deverá retornar layout criado pelo ViewHolder já inflado em uma view.
  • onBindViewHolder(ViewHolder holder, int position): Método que recebe o ViewHolder e a posição da lista. Aqui é recuperado o objeto da lista de Objetos pela posição e associado à ViewHolder. É onde a mágica acontece!
  • getItemCount(): Método que deverá retornar quantos itens há na lista. Aconselha-se verificar se a lista não está nula como no exemplo, pois ao tentar recuperar a quantidade da lista nula pode gerar um erro em tempo de execução (NullPointerException).

Vale ressaltar que os métodos onCreateViewHolder e onBindViewHolder não são chamados para todos os itens inicialmente, eles são chamados apenas para os itens visíveis para o usuário. Quando o usuário sobe e desce a lista, estes dois métodos são chamados novamente associando a view reciclada ao conteúdo daquela posição que agora será visível.

Agora é a hora de voltarmos ao nosso MainActivity.java e programar a integração da RecyclerView com os dados da ClienteDAO. Primeiro, crie um método configurarRecycler, como abaixo:

E depois, chame esse configurarRecycler() no final do onCreate da MainActivity.java, para que ele seja disparado e popule inicialmente a RecyclerView com a lista de clientes do banco.

Isso deve funcionar parcialmente. Quando abrimos o app pela primeira vez ele vai listar corretamente todos os clientes. Mas quando adicionamos um novo cliente, ele não se atualiza.

Até poderíamos resolver isso facilmente mandando chamar novamente o configurarRecycler() a cada nova inserção, mas essa não é a maneira correta de fazer. Ao invés disso, quando um cliente novo for inserido no banco, ele também deve ser inserido na coleção de clientes que o ClienteAdapter referencia, em memória. Para isso, vamos fazer alguns ajustes.

Primeiro, vamos criar um método no ClienteDAO.java para retornar o último Cliente inserido no banco de dados. Isso porque como o ID é automático e autoincremental, precisamos saber o ID que o cliente recebeu para adicionar o objeto completo na nossa lista (usaremos esse ID mais tarde na edição e exclusão). O código é bem parecido com o de retornarTodos, mais simples até, então dispensa explicações:

Agora vamos editar o nosso ClienteAdapter.java para ter um método que adicione novos clientes à lista:

Bem simples, apenas adiciona o cliente na coleção in-memory e notifica a RecyclerView que ela deve se atualizar.

Agora, no nosso click do botão de salvar, após salvar, vamos pegar o último elemento e adicionar ele no adapter usando o método que já está pronto nele, que inclusive atualiza o RecyclerView na sequência. Note que o trecho de código abaixo é o último bloco do onClick do btnSalvar e eu apenas coloquei duas linhas novas no início do if:

Com isso, as duas primeiras letras do CRUD estão prontas: o C de Create e o R de Read.

Lista funcionando
Lista funcionando

Agora é hora de fazer funcionar aqueles dois botões à direita dos nomes!

Curso React Native

Parte 6: Atualizando Clientes

Agora vamos programar a atualização de clientes. A ideia é a seguinte: o usuário clica no botão de editar, daí abrimos a mesma tela de cadastro, mas com os dados do cliente que está sendo editado já preenchido. Daí quando o usuário clica em Salvar, ele faz um update no banco ao invés de um insert.

Para fazer isso, primeiro vamos editar o nosso ClienteDAO para incluir uma sobrecarga do método salvar que recebe um id por parâmetro, informando que é uma atualização ao invés de uma inserção. Não apenas isso, mas achei mais interessante jogar fora aquele método salvar antigo e no lugar adicionei as duas versões abaixo (com e sem id):

Muito menor e mais inteligente!

Agora precisamos editar nossa classe ClienteAdapter.java, que é quem possui a lógica dos botões para programar o click do btnEditar. Primeiro, vamos começar adicionando este método que permite obter uma Activity a partir de uma View qualquer, algo útil considerando que o ClienteAdapter não é uma Activity:

Agora, ainda no ClienteAdapter.java, mas dentro do método onBindViewHolder, adicione o seguinte bloco de código no final do método:

Isso vai fazer com que, ao clicar no botão de editar de alguma das linhas da RecyclerView, seja disparado um “refresh” na Activity atual, passando o cliente que deve ser editado feito Extra.

Aproveitando que estamos aqui no ClienteAdapter.java, vamos adicionar um último método pra ele permitir a atualização fácil e rápida de clientes na RecyclerView mais tarde, no final desta etapa:

Apenas adicione o método acima na ClienteAdapter.java, que tem mecânica semelhante com outros método que também adicionamos por lá, e vamos continuar!

Voltando à MainActivity.java, adicione o seguinte bloco de código na classe:

Basicamente aqui temos uma variável que usaremos pra guardar o cliente que será editado e um método utilitário para selecionarmos o item de um Spinner a partir de seu valor, que usaremos mais tarde.

Agora, ainda no MainActivity.java, mas dentro do método onCreate, adicione esta verificação logo após o setContentView:

Isso faz com que, se estiver vindo um Cliente no Intent que disparou esta Activity, vamos abrir o app na tela de edição ao invés de listagem, já carregando os campos com os valores atuais do cliente.

Para finalizar, temos que fazer com que o botão de salvar seja mais inteligente do que atualmente é. Hoje ele sempre manda salvar um novo cliente, mas agora queremos que ele veja se estamos editando um novo cliente (através da variável clienteEditado) ou se estamos salvando um novo cliente. No código abaixo, eu apenas alterei poucas linhas dentro do onClick do btnSalvar, colocando um if onde antes era apenas uma chamada a dao.salvar:

Isso é o suficiente para fazer com que a nossa edição funcione tão bem quanto as demais operações do nosso app de CRUD.

Editando cliente
Editando cliente

E com isso terminamos a letra U do nosso CRUD!

Parte 7: Removendo Clientes

Agora vamos programar a exclusão de clientes. A ideia é a seguinte: o usuário clica no botão de excluir, daí pedimos uma confirmação e, se ele confirmar, mandamos o ClienteDAO excluir o cliente e removemos o objeto do ClienteAdapter, notificando a lista para que seja atualizada.

Para fazer isso, primeiro vamos editar nossa classe ClienteDAO.java para que tenha um método de exclusão de Cliente:

Agora, vamos editar a classe ClienteAdapter.java para ter um método de exclusão lá também:

Aqui pegamos a posição do cliente que queremos excluir, removemos ele da lista e depois notificamos a RecyclerView.

Agora vamos juntar as pontas mexendo no onBindViewHolder do ClienteAdapter.java novamente, adicionando o listener ao click do btnExcluir presente nos itens da lista. Aqui temos de exibir um popup de confirmação para o usuário e, em caso afirmativo, realizar a exclusão de facto chamando os métodos que criamos anteriormente:

E o mais incrível, funciona!

Exclusão funcionando
Exclusão funcionando

E com isso terminamos a última letra do CRUD, a D de Delete!

Espero que tenham gostado deste mega tutorial. Deu uma trabalheira fazer mas tenho certeza de que ficou uma ótima referência pro pessoal que está querendo fazer um CRUD completo com boas práticas e componentes modernos.

Precisando de referências mais completas quanto ao uso do SQLiteDatabase, consulte a documentação oficial.

Tendo qualquer dúvida, chama aí nos comentários!

Gostou do tutorial e quer mais? Dá uma olhada no meu livro clicando no banner abaixo!

Criando apps para empresas com Android