📚 Pré-requisitos Teóricos: este projeto aplica conceitos ensinados na Especialização em Android Nativo. Recomendado revisar antes de iniciar.

💾 P06: Meus Jogos Favoritos (Catálogo Offline com Room)

v1.0 — Android Jetpack, Kotlin, Room Database (SQLite), Padrão DAO, Coroutines e StateFlow Reativo

Série Prática Android Clássico — Projeto 6 de 21


🏛️ Visão Geral & Arquitetura Visual

O projeto Meus Jogos Favoritos aborda a camada de persistência estruturada recomendada pelo Google no ecossistema Android moderno: o Room Persistence Library. A aplicação implementa uma camada de abstração elegante sobre o SQLite relacional, com validação de consultas SQL em tempo de compilação, operações assíncronas em segundo plano com Kotlin Coroutines (Dispatchers.IO) e fluxo de dados reativo contínuo via Flow / StateFlow.

Arquitetura de Persistência com Room Database

📁 Estrutura de Pastas Anti-Colisão

Os modelos, DAOs, base de dados e componentes de interface estão organizados na subpasta canônica mobile-android-kotlin/:

catalogo_projetos/android_p06_jogos_room/
├── assets/
│   └── arquitetura_jogos_room.svg
├── mobile-android-kotlin/
│   ├── app/
│   │   ├── src/
│   │   │   └── main/
│   │   │       ├── java/br/com/curso/jogosroom/
│   │   │       │   ├── data/
│   │   │       │   │   ├── JogoEntity.kt
│   │   │       │   │   ├── JogoDao.kt
│   │   │       │   │   └── AppDatabase.kt
│   │   │       │   └── MainActivity.kt
│   │   │       └── res/
│   │   └── build.gradle
│   ├── gradle/
│   ├── build.gradle
│   ├── gradlew
│   ├── settings.gradle
│   └── README.md
└── index.md

🧑‍💼 Engenharia de Software & Especificação Formal

1. Histórias de Usuário (User Stories)

ID Persona Narrativa da Funcionalidade Critério de Aceitação Principal Prioridade
US-01 Gamer / Colecionador Quero cadastrar novos jogos informando título, plataforma e nota de avaliação. Gravação imediata no banco Room e atualização automática da lista visual. Alta
US-02 Gamer / Colecionador Quero visualizar todos os jogos cadastrados mesmo com o smartphone em modo avião. Recuperação dos registros locais a partir da tabela SQLite sem depender de rede. Alta
US-03 Gamer / Colecionador Quero filtrar ou ordenar jogos por plataforma ou melhor nota. Consulta SQL reativa filtrando itens em tempo real. Média
US-04 Gamer / Colecionador Quero excluir jogos desinstalados da minha lista com confirmação. Remoção atômica do registro no banco através do método anotado @Delete. Média
US-05 Desenvolvedor Mobile Quero que as operações de I/O nunca ocorram na thread principal para evitar ANR. Execução estrita das funções suspensas no despachante Dispatchers.IO. Baixa

2. Requisitos do Sistema

Requisitos Funcionais (RF)

Requisitos Não-Funcionais (RNF)


3. Diagrama de Casos de Uso

flowchart TD
    User([fa:fa-user Usuário / Colecionador])
    Room[(fa:fa-database Room SQLite)]

    subgraph AppRoom ["💾 Catálogo de Jogos (mobile-android-kotlin)"]
        UC01["Cadastrar Novo Jogo"]
        UC02["Listar Jogos em Tempo Real"]
        UC03["Filtrar por Plataforma"]
        UC04["Excluir Registro de Jogo"]
        UC05["Consultar Estatísticas Locais"]
    end

    User --> UC01
    User --> UC02
    User --> UC03
    User --> UC04
    UC01 --> Room
    Room -.->|Flow| UC02
    UC04 --> Room

4. Matriz de Rastreabilidade (RTM)

ID Requisito História de Usuário Artefato de Código Teste de Aceitação
RF-01 US-01 mobile-android-kotlin/app/.../JogoEntity.kt testEntityTableMapping()
RF-02 US-01, US-04 mobile-android-kotlin/app/.../JogoDao.kt testInsertAndQueryGameDao()
RF-03 US-02 mobile-android-kotlin/app/.../JogoDao.kt testFlowEmitsOnNewRecord()
RF-04 US-05 mobile-android-kotlin/app/.../AppDatabase.kt testDatabaseSingletonInstance()
RF-05 US-01 mobile-android-kotlin/app/.../MainActivity.kt testFormValidationOnSubmit()

🛠️ Implementação Guiada (JogoDatabase.kt)

📄 mobile-android-kotlin/app/src/main/java/br/com/curso/colecaojogos/data/local/JogoDatabase.kt (arquivo real do projeto)

package br.com.curso.colecaojogos.data.local

import android.content.Context
import androidx.room.*
import kotlinx.coroutines.flow.Flow

// 1. A TABELA (Entity)
@Entity(tableName = "jogos")
data class Jogo(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val nome: String,
    val plataforma: String
)

// 2. O CONTROLE REMOTO (DAO)
@Dao
interface JogoDao {
    @Insert
    suspend fun inserir(jogo: Jogo)

    @Query("SELECT * FROM jogos ORDER BY id DESC")
    fun listarTodos(): Flow<List<Jogo>>

    @Delete
    suspend fun deletar(jogo: Jogo)
}

// 3. A CENTRAL (Database)
@Database(entities = [Jogo::class], version = 1)
abstract class JogoDatabase : RoomDatabase() {
    abstract fun jogoDao(): JogoDao

    companion object {
        @Volatile
        private var INSTANCE: JogoDatabase? = null

        fun getDatabase(context: Context): JogoDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    JogoDatabase::class.java,
                    "jogo_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

🚀 Como Executar no Laboratório

1. Navegue até a subpasta do projeto

cd catalogo_projetos/android_p06_jogos_room/mobile-android-kotlin

2. Compile e execute os testes unitários do Room

./gradlew test
./gradlew connectedAndroidTest

🏁 Matriz de Checkpoints de Conclusão

Checkpoint Meta Técnica Critério de Aceite Status
CP-01 Esquema Room Compilado Entidades e DAOs gerando classes de implementação via KSP PASS ✅
CP-02 Persistência Offline Dados persistem após fechar e reabrir o aplicativo PASS ✅
CP-03 Fluxo Reativo com Flow UI atualizada automaticamente ao inserir ou excluir itens PASS ✅
CP-04 Coroutines Dispatchers.IO Zero chamadas de banco bloqueando a thread principal PASS ✅
CP-05 Suíte de Testes Automatizados Testes de unidade em memória com Room.inMemoryDatabaseBuilder PASS ✅