💻 Exemplos: Capítulo 13: Persistência Local com Room Database
Exemplos de Código: Capítulo 13 — Persistência com Room Database
Especialização em Mobile Nativo com Android • Demonstrações Práticas Compiláveis
💻 Código de Demonstração: @Entity, @Dao, Consultas Reativas com Flow e RoomDatabase
O código abaixo demonstra a arquitetura oficial de persistência SQLite no Android com a biblioteca Jetpack Room:
- Modelagem de tabela com a anotação
@Entitye chaves primárias automáticas. - Contrato de operações CRUD assíncronas no
@Daocom suporte nativo aFlowreativo (notifica a UI automaticamente a cada mutação de dados). - Configuração de
RoomDatabasee padrão Repository para isolamento de dados.
package br.com.portal.mobile.android.cap13
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
// =====================================================================
// 1. Entidade de Banco de Dados (@Entity)
// =====================================================================
/*
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Delete
import androidx.room.Database
import androidx.room.RoomDatabase
*/
// @Entity(tableName = "tarefas")
data class TarefaEntity(
// @PrimaryKey(autoGenerate = true)
val id: Long = 0,
val titulo: String,
val descricao: String,
val concluida: Boolean = false,
val criadaEm: Long = System.currentTimeMillis()
)
// =====================================================================
// 2. Data Access Object (@Dao)
// =====================================================================
// @Dao
interface TarefaDao {
// @Query("SELECT * FROM tarefas ORDER BY criadaEm DESC")
fun listarTodas(): Flow<List<TarefaEntity>>
// @Query("SELECT * FROM tarefas WHERE id = :id LIMIT 1")
suspend fun buscarPorId(id: Long): TarefaEntity?
// @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun inserir(tarefa: TarefaEntity): Long
// @Query("UPDATE tarefas SET concluida = :status WHERE id = :id")
suspend fun atualizarStatus(id: Long, status: Boolean)
// @Delete
suspend fun remover(tarefa: TarefaEntity)
}
// =====================================================================
// 3. Definição do Banco de Dados (@Database)
// =====================================================================
/*
@Database(entities = [TarefaEntity::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun tarefaDao(): TarefaDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"portal_tarefas.db"
).build()
INSTANCE = instance
instance
}
}
}
}
*/
// =====================================================================
// 4. Repositório Corporativo Desacoplado
// =====================================================================
class TarefasRepository(private val dao: TarefaDao) {
val todasTarefas: Flow<List<TarefaEntity>> = dao.listarTodas()
suspend fun cadastrarTarefa(titulo: String, descricao: String) {
val nova = TarefaEntity(titulo = titulo, descricao = descricao)
dao.inserir(nova)
}
suspend fun alternarConclusao(id: Long, concluida: Boolean) {
dao.atualizarStatus(id, concluida)
}
}
// =====================================================================
// 5. Simulação de Teste em Memória
// =====================================================================
class FakeTarefaDao : TarefaDao {
private val tabela = mutableListOf<TarefaEntity>()
override fun listarTodas(): Flow<List<TarefaEntity>> = flowOf(tabela.toList())
override suspend fun buscarPorId(id: Long): TarefaEntity? = tabela.find { it.id == id }
override suspend fun inserir(tarefa: TarefaEntity): Long {
val gerado = (tabela.size + 1).toLong()
val salva = tarefa.copy(id = gerado)
tabela.add(salva)
return gerado
}
override suspend fun atualizarStatus(id: Long, status: Boolean) {
val idx = tabela.indexOfFirst { it.id == id }
if (idx != -1) {
tabela[idx] = tabela[idx].copy(concluida = status)
}
}
override suspend fun remover(tarefa: TarefaEntity) {
tabela.removeIf { it.id == tarefa.id }
}
}
fun main() = runBlocking {
println("=== PERSISTÊNCIA LOCAL COM ROOM DATABASE ===")
val fakeDao = FakeTarefaDao()
val repo = TarefasRepository(fakeDao)
repo.cadastrarTarefa("Finalizar Curso Android", "Implementar 20 capítulos no Padrão Ouro")
repo.cadastrarTarefa("Estudar Jetpack Compose", "Praticar Modifiers e Room")
repo.todasTarefas.collect { lista ->
println("Tarefas persistidas no banco local (${lista.size} registros):")
lista.forEach {
val check = if (it.concluida) "[X]" else "[ ]"
println(" -> $check ID ${it.id}: ${it.titulo} (${it.descricao})")
}
}
}