Projeto: app Forage

1. Antes de começar

Este codelab apresenta um novo app, chamado Forage, que você vai criar por conta própria. O codelab mostra os passos para concluir o projeto do app Forage, incluindo a configuração dele e os testes no Android Studio.

Pré-requisitos

  • Este projeto é destinado aos alunos que concluíram a Unidade 5 do curso Noções básicas do Android no Kotlin.

O que você vai criar

  • Você vai usar o Room para adicionar persistência a um app existente implementando uma entidade, DAO, ViewModel e uma classe de banco de dados.

Pré-requisitos

  • Um computador com o Android Studio instalado.

2. Visão geral do app final

O app Forage final permite que os usuários registrem itens, como alimentos, encontrados por eles na natureza. Esses dados são mantidos entre as sessões usando o Room. Você vai usar seu conhecimento sobre o Room e execução de operações de leitura, gravação, atualização e exclusão de dados em um banco de dados para implementar a persistência no app Forage. Veja uma descrição sobre a versão final do app e as funções oferecidas abaixo.

Quando o app for iniciado pela primeira vez, o usuário vai ver uma tela vazia contendo uma visualização de reciclagem, que exibe os itens encontrados, além de um botão flutuante no canto direito de baixo para adicionar novos itens.

3edd87e63c387d88.png

Ao adicionar um novo item, o usuário pode especificar um nome, o local onde ele foi encontrado e incluir algumas outras observações. Há também uma caixa de seleção para indicar se esse é ou não um alimento da estação.

6c0c739569bb3b4f.png

Após ser adicionado, o item aparece na visualização da reciclagem na primeira tela.

bcc75e60b70320e8.png

Ao tocar em um item, uma tela de detalhes é exibida, mostrando o nome, o local e as observações sobre o item.

5096995a4921dcac.png

O botão flutuante também muda de um símbolo de adição para um ícone de edição. Ao tocar nesse botão, o app abre uma tela que permite que o usuário edite o nome, o local, as observações e a caixa de seleção "in season" (da estação). Já o botão "Delete" (excluir) remove o item do banco de dados.

f8c708fed3dede1a.png

Embora a parte relacionada à IU do app já tenha sido implementada, sua tarefa é implementar a persistência usando seu conhecimento sobre o Room para que o app leia, grave, atualize e exclua itens do banco de dados.

3. Primeiros passos

Fazer o download do código do projeto

O nome da pasta é android-basics-kotlin-forage-app. Selecione essa pasta ao abrir o projeto no Android Studio.

Para encontrar o código deste codelab e abri-lo no Android Studio, faça o seguinte.

Acessar o código

  1. Clique no URL fornecido. Isso abrirá a página do GitHub referente ao projeto em um navegador.
  2. Na página do GitHub do projeto, clique no botão Code, que vai mostrar uma caixa de diálogo.

5b0a76c50478a73f.png

  1. Na caixa de diálogo, clique no botão Download ZIP para salvar o projeto no seu computador. Aguarde a conclusão do download.
  2. Localize o arquivo no computador, que provavelmente está na pasta Downloads.
  3. Clique duas vezes para descompactar o arquivo ZIP. Isso criará uma nova pasta com os arquivos do projeto.

Abrir o projeto no Android Studio

  1. Inicie o Android Studio.
  2. Na janela Welcome to Android Studio, clique em Open an existing Android Studio project.

36cc44fcf0f89a1d.png

Observação: caso o Android Studio já esteja aberto, selecione a opção File > New > Import Project.

21f3eec988dcfbe9.png

  1. Na caixa de diálogo Import Project, vá até a pasta do projeto descompactada, que provavelmente está na pasta Downloads.
  2. Clique duas vezes nessa pasta do projeto.
  3. Aguarde o Android Studio abrir o projeto.
  4. Clique no botão Run 11c34fc5e516fb1c.png para criar e executar o app. Confira se ele é compilado da forma esperada.
  5. Procure os arquivos do projeto na janela de ferramentas Project para ver como o app está configurado.

4. Configurar o projeto para usar o Room

Definir a entidade Forageable

O projeto já tem uma classe Forageable que define os dados do app (model.Forageable.kt). Essa classe tem várias propriedades: id, name, address, inSeason e notes.

data class Forageable(
   val id: Long = 0,
   val name: String,
   val address: String,
   val inSeason: Boolean,
   val notes: String?
)

No entanto, para usar essa classe a fim de armazenar dados persistentes, é necessário a converter em uma entidade do Room.

  1. Adicione a anotação @Entity à classe, com o nome da tabela "forageable_database".
  2. Defina a propriedade id como a chave primária. A chave primária precisa ser gerada automaticamente.
  3. Defina o nome da coluna da propriedade inSeason como "in_season".

Implementar o DAO

O ForageableDao (data.ForageableDao.kt), como você pode imaginar, é o local em que você define métodos para ler e gravar no banco de dados e é acessado do modelo de visualização. Como o DAO é apenas uma interface que você define, não é necessário escrever nenhum código para implementar esses métodos. Em vez disso, use anotações do Room, especificando a consulta SQL quando necessário.

Na interface ForageableDao, é necessário adicionar cinco métodos.

  1. Um método getForageables() que retorna um Flow<List<Forageable>> para todas as linhas no banco de dados.
  2. Um método getForageable(id: Long) que retorna um Flow<Forageable> que corresponde ao id especificado.
  3. Um método insert(forageable: Forageable) que insere um novo item Forageable no banco de dados.
  4. Um método update(forageable: Forageable) que usa um item Forageable como parâmetro e atualiza a linha corretamente.
  5. Um método delete(forageable: Forageable) que usa um item Forageable como parâmetro e o exclui do banco de dados.

Implementar o modelo de visualização

O ForageableViewModel (ui.viewmodel.ForageableViewModel.kt) já foi parcialmente implementado, mas ainda é necessário adicionar uma funcionalidade que acesse os métodos DAO para que ele possa realmente ler e gravar dados. Siga as etapas abaixo para implementar o ForageableViewModel.

  1. Uma instância do ForageableDao precisa ser transmitida como um parâmetro no construtor da classe.
  2. Crie uma variável do tipo LiveData<List<Forageable>> que receba a lista inteira de entidades Forageable usando o DAO e converta o resultado em LiveData.
  3. Crie um método que use um ID do tipo Long como parâmetro e retorne um LiveData<Forageable> da chamada do método getForageable() no DAO e da conversão do resultado em LiveData.
  4. No método addForageable(), inicie uma corrotina usando o viewModelScope e use o DAO para inserir a instância Forageable no banco de dados.
  5. No método updateForageable(), use o DAO para atualizar a entidade Forageable.
  6. No método deleteForageable(), use o DAO para atualizar a entidade Forageable.
  7. Crie uma ViewModelFactory que possa criar uma instância do ForageableViewModel com um parâmetro de construtor ForageableDao.

Implementar a classe do banco de dados

A classe ForageDatabase (data.ForageDatabase.kt) é responsável por expor as entidades e o DAO ao Room. Implemente a classe ForageDatabase conforme descrito.

  1. Entidades: Forageable
  2. Versão: 1
  3. exportSchema: false
  4. Na classe ForageDatabase, inclua uma função abstrata para retornar um ForageableDao.
  5. Na classe ForageDatabase, defina um objeto complementar com uma variável particular com o nome INSTANCE e uma função getDatabase() que retorna o Singleton ForageDatabase.
  1. Na classe BaseApplication, crie uma propriedade database que retorne uma instância de ForageDatabase usando a inicialização lenta.

5. Manter e ler dados de fragmentos

Depois de configurar as entidades, o DAO, o modelo de visualização e definir a classe de banco de dados para expor essas entidades ao Room, ainda é necessário modificar os fragmentos a fim de acessar o modelo de visualização. Você precisa modificar três arquivos, um para cada tela do app.

Lista de itens encontrados

Essa tela requer apenas dois itens: uma referência ao modelo de visualização e acesso à lista completa de itens encontrados. Execute as tarefas abaixo em ui.ForageableListFragment.kt.

  1. A classe já tem uma propriedade viewModel. No entanto, ela não está usando a fábrica definida na etapa anterior. Primeiramente, é necessário refatorar essa declaração para usar a ForageableViewModelFactory.
private val viewModel: ForageableViewModel by activityViewModels {
   ForageableViewModelFactory(
       (activity?.application as BaseApplication).database.foragableDao()
   )
}
  1. No método onViewCreated(), observe a propriedade allForageables do viewModel e chame submitList() no adaptador, quando adequado, para preencher a lista.

Tela de detalhes dos itens encontrados

Você vai fazer quase o mesmo para a lista de detalhes em ui/ForageableDetailFragment.kt.

  1. Converta a propriedade do viewModel para inicializar a ForageableViewModelFactory corretamente.
  2. No método onViewCreated(), chame getForageable() no modelo de visualização, transmitindo o id para receber a entidade Forageable. Observe os dados dinâmicos e defina o resultado como a propriedade forageable. Em seguida, chame bindForageable() para atualizar a IU.

Adicionar e editar a tela de itens encontrados

Por fim, você precisa realizar um procedimento semelhante em ui.AddForageableFragment.kt. Essa tela também é responsável por atualizar e excluir entidades. No entanto, esses métodos do modelo de visualização já são chamados no lugar correto. Por isso, você só vai precisar fazer duas mudanças no arquivo.

  1. Novamente, refatore a propriedade do viewModel para usar a ForageableViewModelFactory.
  2. No método onViewCreated(), no bloco de instruções "if" antes de definir a visibilidade do botão "Delete", chame getForageable() no modelo de visualização, transmitindo o id e definindo o resultado da propriedade forageable.

Isso é tudo o que você precisa fazer nos fragmentos. Agora, você pode executar o app e ver toda a funcionalidade de persistência em ação.

6. Instruções sobre testes

Como executar os testes

Para executar os testes, escolha uma das opções abaixo.

Para um único caso de teste, abra uma classe de caso de teste PersistenceInstrumentationTests.kt e clique na seta verde à esquerda da declaração da classe. Em seguida, selecione a opção "Run" no menu. Isso vai executar todos os testes do caso.

3e640ec727599a6d.png

Na maioria das vezes, convém executar apenas um teste, por exemplo, se apenas um teste for reprovado e os outros forem aprovados. Você pode executar um único teste da mesma forma que faria com todo o caso de teste. Use a seta verde e selecione a opção Run.

8647a76419540499.png

Se você tem vários casos de teste, também pode executar todo o conjunto de testes. Assim como na execução do app, você encontra essa opção no menu Run.

7a925c5e196725bb.png

O Android Studio usa como padrão o último destino que você executou (app, destinos de teste etc.). Portanto, se o menu ainda exibir Run > Run 'app', você pode executar o destino de teste selecionando Run > Run.

90d3ec5ca5928b2a.png

Em seguida, escolha o destino do teste no menu pop-up.

3b1a7d82a55b5f13.png