Livro 3 - Projeto Agenda de Contatos - Parte 3
3. Biblioteca Room e persistência de dados
3.5. Classe ContactsRepository (Repository)
O que é um Repositório?
A classe Repository é uma classe que abstrai o acesso a múltiplas fontes de dados. O repositório não é um componente de arquitetura do Android JetPack mas é uma prática recomendada. Um repositório manipula operações sobre as fontes de dados e oferece uma API limpa para ser usada pelo resto da aplicação. A figura abaixo ilustra como o camada repositório se encaixa na arquitetura do projeto. Note que UI se refere a User Interface, ou seja, a interface gráfica.
Porque usar um Repositório?
Um repositório gerencia as threads das consultas e permite o uso de múltiplas fontes de dados. Em um caso de uso mais comum, o repositório implementa a lógica para decidir de os dados devem ser obtidos através de um Web Service ou de uma cache armazenada em um banco de dados local.
Implementando a classe ContactsRepository
A classe ContactsRepository implementará todas as operações necessárias para o aplicativo Agenda de Contatos. Para cada consulta ao banco será usada uma AsyncTask para executar a operação em plano de fundo.
package ...
import android.app.Application;
import android.os.AsyncTask;
import androidx.lifecycle.LiveData;
import java.util.List;
public class ContactsRepository {
private ContactsDAO mContactsDao;
private LiveData<List<Contact>> mAllContacts; // create a cached data
public ContactsRepository(Application application) {
ContactsDatabase db = ContactsDatabase.getDatabase(application);
mContactsDao = db.contactsDao();
mAllContacts = mContactsDao.getAllContacts();
}
/***********************************************
GET ALL CONTACTS
***********************************************/
public LiveData<List<Contact>> getAllContacts() {
return mAllContacts;
}
/***********************************************
GET CONTACT BY ID
***********************************************/
public LiveData<Contact> getContactById(int id) {
return mContactsDao.getContactById(id);
}
/***********************************************
INSERT CONTACT TASKS
***********************************************/
public void insert (Contact contact) {
new insertAsyncTask(mContactsDao).execute(contact);
}
private static class insertAsyncTask extends AsyncTask<Contact, Void, Void> {
private ContactsDAO mAsyncTaskDao;
insertAsyncTask(ContactsDAO dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Contact... params) {
mAsyncTaskDao.insert(params[0]);
return null;
}
}
/***********************************************
UPDATE CONTACT TASKS
***********************************************/
public void update (Contact contact) {
new updateAsyncTask(mContactsDao).execute(contact);
}
private static class updateAsyncTask extends AsyncTask<Contact, Void, Void> {
private ContactsDAO mAsyncTaskDao;
updateAsyncTask(ContactsDAO dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Contact... params) {
mAsyncTaskDao.update(params[0]);
return null;
}
}
/***********************************************
DELETE CONTACT TASKS
***********************************************/
public void delete (Contact contact) {
new deleteAsyncTask(mContactsDao).execute(contact);
}
private static class deleteAsyncTask extends AsyncTask<Contact, Void, Void> {
private ContactsDAO mAsyncTaskDao;
deleteAsyncTask(ContactsDAO dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Contact... params) {
mAsyncTaskDao.delete(params[0]);
return null;
}
}
}
- O repositório cria dois objetos em seu construtor para serem usados ao longo do aplicativo. mContactsDAO representa o DAO para executar as operações no banco de dados e mAllContacts representa a lista de contatos.
- Observe que não foi implementando um método para buscar todos os contatos. Isso ocorre durante o construtor e será invocado logo no inicio do aplicativo apenas uma vez. Quando um contato for adicionado, alterado ou removido, você deve imaginar que a lista de contatos deveria ser atualizada e um nova consulta ao banco de dados solicitado para exibir na tela essas novas informações. No entanto, estamos usando LiveData e assim não precisamos fazer uma nova solicitação pois qualquer mudança a lista de contatos será automaticamente processada! Assim, ao ser chamado o método getAllContacts podemos simplesmente retornar a lista de objetos LiveData sem ter que fazer explicitamente uma nova solicitação ao banco de dados com o DAO.
- Ademais, no caso de ser buscado as informações de um contato específico precisamos apenas fazer a solicitação ao DAO pois ele irá automaticamente buscar o valor salvo na cache da consulta já feita logo não será uma tarefa demorada.
- Para as demais operações, usamos uma AsyncTask para configurar uma ação em segunda plano e executar o método apropriado do DAO.
Classe AsyncTask
A classe AsyncTask é um classe que permite facilmente a declaração de ações para serem executadas em segundo plano sem você ter que manipular explicitamente threads. Essa classe é criada com a declaração de três tipos respectivamente um tipo associado aos parâmetros, progresso e resultado. Esses tipos serão usados nos métodos onPreExecute, doInBackground, onProgressUpdate e onPostExecute. Todo código declarado dentro do método doInBackground será executado em uma thread paralela. Você pode então fazer uma solicitação a um Web Service em paralela e após receber os dados executar uma ação, como atualizar os valores na tela, com o método onPostExecute.
No caso do aplicativo da Agenda de Contatos não precisamos de uma ação de retorno pois apenas iremos fazer solicitações para o banco de dados. Logo usar apenas o método doInBackground é o suficiente. Você poderia no entanto, mostrar uma mensagem de sucesso após uma consulta o banco usando o método onPostExecute.