6. Implementação das funcionalidades do Firebase
6.2. Classe TarefaRepository
O que é um Repositório?
No desenvolvimento de software, especialmente em aplicações Kotlin e Java, o Padrão de Repositório (Repository Pattern) é uma prática comum para encapsular operações que interagem com o banco de dados ou APIs externas. O repositório atua como uma camada intermediária entre a aplicação e a fonte de dados, fornecendo uma interface consistente e abstraindo os detalhes da implementação.
Classe TarefaRepository
A classe TarefaRepository encapsula as operações que interagem com o banco de dados, permitindo adicionar, ler, atualizar e deletar objetos do tipo Tarefa. Vamos descrever cada uma dessas operações e como elas podem ser implementadas.
Código da classe:
package ...
import android.util.Log
import androidx.lifecycle.MutableLiveData
import com.google.firebase.auth.ktx.auth
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.ktx.Firebase
class TarefaRepository {
//padrão singleton do Kotlin - garante que existe apenas um objeto do tipo no app
companion object {
private fun getCurrentRef(): DatabaseReference {
//acessa a referência a lista de tarefas do usuário logado
val auth = Firebase.auth
val uuid = auth.uid.toString()
return FirebaseDatabase.getInstance().getReference("tarefas").child(uuid).child("lista")
}
fun carregarTarefa(_tarefas: MutableLiveData<MutableList<Tarefa>>) {
//obtem a referencia a lista de tarefas do usuario
val mTarefasRef = getCurrentRef()
//configura a leitura em tempo real das tarefas para atualizar a lista
mTarefasRef!!.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val listaDeTarefas = mutableListOf<Tarefa>()
for (tarefaSnapshot in snapshot.children) {
val tarefa = tarefaSnapshot.getValue(Tarefa::class.java)
tarefa?.setTarefaId(tarefaSnapshot.key)
tarefa?.let { listaDeTarefas.add(it) }
}
_tarefas.value = listaDeTarefas
}
override fun onCancelled(error: DatabaseError) {
Log.e("TODO2024","Erro ao buscar tarefas: ${error.message}")
}
})
}
fun addTarefa(tarefa: Tarefa) {
val mTarefasRef = getCurrentRef()
mTarefasRef.push().setValue(tarefa).addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("TODO2024","Tarefa criada:" + tarefa.nome)
} else {
Log.w("TODO2024", "Falha ao cadastrar tarefa", task.exception)
}
}
}
fun deleteTarefa(key: String) {
val mTarefasRef = getCurrentRef()
mTarefasRef.child(key).removeValue().addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("TODO2024","Tarefa deletada:" + key)
} else {
Log.w("TODO2024", "Falha ao deletar tarefa", task.exception)
}
}
}
fun updateCondicao(key: String, bool: Boolean) {
if (key == "")
return
val mTarefasRef = getCurrentRef()
mTarefasRef.child(key).child("condicao"). setValue(bool).addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("TODO2024","Tarefa atualizada:" + key)
} else {
Log.w("TODO2024", "Falha ao atualizar tarefa", task.exception)
}
}
}
}
}
Companion object
No Kotlin, companion object é um recurso que permite declarar membros estáticos dentro de uma classe, de forma semelhante ao conceito de membros estáticos em Java. Esses membros pertencem à classe em si, e não às instâncias dela. Você pode usar companion object para definir funções, propriedades e constantes que podem ser acessadas diretamente pela classe. Usamos essa estratégia no repositório para ter fácil acesso as métodos dele ao longo do aplicativo, sem a necessidade de instanciar um objeto.
Método getCurrentRef
O método getCurrentRef retorna a referência ao caminho específico no Firebase, considerando o usuário atualmente logado. No banco de dados, as informações das tarefas de cada usuário serão armazenadas em caminhos separados, seguindo o padrão "tarefas/{uuid}/xxx", onde {uuid} é o código único gerado pelo sistema de autenticação do Firebase.
Essa abordagem garante que os dados de cada usuário sejam salvos de forma isolada, evitando conflitos ou alterações indesejadas em informações de outros usuários. Além disso, ela reforça a segurança e a privacidade, já que um usuário não poderá acessar ou modificar os dados de outro, mesmo que ambos utilizem o mesmo aplicativo.
Método carregarTarefa
O método carregarTarefa recebe um objeto do tipo genérico MutableList. No Kotlin, uma MutableList é uma lista que permite adicionar, remover ou alterar elementos. Ao contrário de uma List (que é imutável), uma MutableList proporciona flexibilidade para modificar os dados conforme necessário, sendo especialmente útil ao trabalhar com coleções dinâmicas.
Além disso, utilizamos um LiveData, especificamente um MutableLiveData. Um LiveData é uma classe observável do Android Jetpack projetada para armazenar e gerenciar dados de forma que as alterações possam ser refletidas automaticamente na interface do usuário. Ela é sensível ao ciclo de vida das atividades e fragmentos, garantindo que os observadores sejam notificados apenas quando esses componentes estiverem no estado ativo. Uma das principais vantagens de usar LiveData é que ele permite fazer atualizações automáticas, sempre que o valor do LiveData muda, a UI é atualizada automaticamente.
Neste contexto, utilizamos o addValueEventListener do Firebase para monitorar alterações em tempo real nos dados. A cada alteração, o Firebase retorna um DataSnapshot contendo os dados atualizados. Percorremos esse snapshot e populamos uma lista interna de tarefas. Após processar os dados, atualizamos o valor do MutableLiveData com a lista, notificando automaticamente a interface do usuário para refletir as novas informações. Isso garante que a UI sempre exiba os dados mais recentes do banco de dados.
Método add, update e delete
Os demais métodos do repositório realizam as operações necessárias no banco de dados usando os caminhos especificados. Assim como no cadastro de usuários, utilizamos o método setValue para adicionar ou atualizar objetos no Firebase. Esse método converte o objeto Kotlin para o formato JSON e o armazena no caminho definido.
Para excluir dados, utilizamos o método removeValue. Esse método apaga o valor armazenado no caminho especificado no Firebase. Por exemplo, ao chamar removeValue em uma referência específica, o Firebase exclui o nó correspondente, garantindo que os dados sejam removidos do banco de forma eficiente.
A execução dessas operações é assíncrona, e podemos processar os resultados usando métodos como addOnCompleteListener para verificar o sucesso ou falha da solicitação.