Aula 19 - Persistência Local com Room DB e Injeção Hilt 💉
Objetivo Pedagógico
Objetivo: Implementar persistência offline-first robusta com Room Database (SQLite), migrações de esquema e injeção de dependências modular com Hilt/Dagger em arquitetura limpa.
📑 1. Fundamentos Teóricos & Análise Técnica
Aplicativos móveis de qualidade industrial devem adotar uma postura Offline-First: o banco de dados local atua como a única fonte da verdade para a interface do usuário, enquanto as requisições de rede atuam como sincronizadores secundários em segundo plano.
O ecossistema Android Jetpack resolve essa complexidade através de: 1. Room Persistence Library: - Camada de abstração sobre o SQLite que provê verificação em tempo de compilação de instruções SQL, prevenindo erros de sintaxe em runtime. - Entidades (@Entity): Mapeamento direto de Data Classes Kotlin para tabelas relacionais com chaves primárias, índices compostos e restrições de unicidade. - Data Access Objects (@Dao): Métodos declarativos com retorno de tipos reativos como Flow<List<T>>, emitindo automaticamente novas listas sempre que dados da tabela sofrem inserção ou alteração. - Migrações Automáticas e Manuais: Evolução de esquema sem perda de dados do usuário através de objetos Migration declarativos. 2. Injeção de Dependências com Hilt (Dagger): - Framework oficial que elimina o boilerplate de instanciação manual de componentes. - Fornece contêineres de injeção amarrados aos ciclos de vida nativos do Android: @Singleton (aplicação), @ActivityRetainedScoped (ViewModel) e @ActivityScoped (Activity).
📐 Arquitetura Conceitual & Diagrama de Fluxo
graph TD
App["Application Context (@HiltAndroidApp)"] --> Singleton["Módulo Hilt de Banco (@Singleton)"]
Singleton --> RoomDB["Room Database Instance"]
RoomDB --> Dao["OrderDao (@Dao)"]
Dao --> Repo["OrdersRepositoryImpl (@Inject)"]
Repo --> VM["OrdersViewModel (@HiltViewModel)"]
VM --> UI["Compose Screen"]
RoomDB -.->|Emite Flow Reativo| Dao
Dao -.->|Flow<List<Order>>| Repo
Repo -.->|Flow| VM
style App fill:#e1f5fe,stroke:#01579b
style RoomDB fill:#fff3e0,stroke:#e65100
style Repo fill:#f3e5f5,stroke:#7b1fa2
style VM fill:#e8f5e9,stroke:#2e7d32
style UI fill:#e0f2f1,stroke:#00695c 🔍 Pilares e Diretrizes Técnicas
Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Verificação SQL em Tempo de Compilação: O Room analisa cada query anotada com @Query durante o build do Gradle, garantindo tipagem correta. - Arquitetura Offline-First Reativa: A UI consome o Flow emitido pelo DAO; quando o worker de rede salva novos registros, a tela atualiza-se sozinha. - Inversão de Dependências com Hilt: Desacoplamento de interfaces e implementações facilitando a substituição por fakes/mocks em testes unitários. - Migração Segura de Versão de Banco: Preservação da integridade estrutural das tabelas SQLite entre updates do app na Play Store.
🛠️ 2. Implementação Prática em Persistência Relacional Android e Injeção de Dependências
Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:
// OrderDatabaseAndHilt.kt (Room DAO Reativo e Módulo de Injeção Hilt)
package com.portal.android.data
import androidx.room.*
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Entity(tableName = "orders_table")
data class OrderEntity(
@PrimaryKey val id: String,
val title: String,
val amount: Double,
val createdAt: Long = System.currentTimeMillis()
)
@Dao
interface OrderDao {
@Query("SELECT * FROM orders_table ORDER BY createdAt DESC")
fun getAllOrdersStream(): Flow<List<OrderEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertOrders(orders: List<OrderEntity>)
@Query("DELETE FROM orders_table WHERE id = :orderId")
suspend fun deleteOrder(orderId: String)
}
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideOrderDao(db: AppDatabase): OrderDao = db.orderDao()
}
💡 Análise Passo a Passo do Código
- Retorno em
Flow<List<OrderEntity>>: Cria um canal de comunicação reativo direto do banco SQLite até a camada de apresentação Compose. - Estratégia
OnConflictStrategy.REPLACE: Garante idempotência em operações de sincronização em massa vindas de APIs externas. - Injeção via
SingletonComponent: Assegura que apenas uma única instância de conexão SQLite permaneça ativa no ciclo de vida do processo.
🎯 3. Próximos Passos & Sequência Didática
-
Slides da Aula
-
Quiz de Fixação
-
Exercícios Práticos
-
Desafio de Projeto