SQLite no Android com Kotlin: Persistência Local na Prática
← Voltar para o blog
Kotlin
1207 views5 min de leitura

SQLite no Android com Kotlin: Persistência Local na Prática

Quando falamos em armazenamento local mais estruturado no Android, o SQLite é uma das bases mais importantes da plataforma. Diferente de soluções como SharedPreferences ou DataStore, ele permite trabalhar com dados relacionais, consultas mais complexas e maior controle sobre o armazenamento. Neste guia, você vai entender como utilizar o SQLite com Kotlin, quando faz sentido adotá-lo e quais cuidados tomar em projetos reais.

Publicado em 27 de janeiro de 2026 às 17:04

O que é SQLite?

O SQLite é um banco de dados relacional leve, embutido no próprio Android. Isso significa que você não precisa instalar nada adicional — ele já faz parte do sistema.

Com ele, você pode:

  • criar tabelas

  • inserir, atualizar e remover dados

  • realizar consultas com SQL

  • trabalhar com relacionamentos

É uma excelente escolha quando você precisa de persistência local mais robusta.


Quando usar SQLite?

Use SQLite quando:

  • precisa armazenar dados estruturados

  • precisa fazer consultas com filtros, ordenações ou joins

  • o volume de dados começa a crescer

  • há necessidade de consistência e integridade

Evite quando:

  • dados são simples (prefira DataStore)

  • precisa apenas de cache leve

  • não há necessidade de consultas complexas


Criando um banco com SQLiteOpenHelper

No Android, a forma tradicional de usar SQLite é através da classe SQLiteOpenHelper.

Exemplo básico

class DatabaseHelper(context: Context) :
    SQLiteOpenHelper(context, "app.db", null, 1) {

    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL("""
            CREATE TABLE usuario (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                nome TEXT,
                email TEXT
            )
        """.trimIndent())
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS usuario")
        onCreate(db)
    }
}

Aqui você define:

  • criação das tabelas

  • estratégia de versionamento


Inserindo dados

fun inserirUsuario(nome: String, email: String) {
    val db = writableDatabase

    val values = ContentValues().apply {
        put("nome", nome)
        put("email", email)
    }

    db.insert("usuario", null, values)
}

Consultando dados

fun listarUsuarios(): List<String> {
    val db = readableDatabase
    val cursor = db.rawQuery("SELECT nome FROM usuario", null)

    val lista = mutableListOf<String>()

    while (cursor.moveToNext()) {
        lista.add(cursor.getString(0))
    }

    cursor.close()
    return lista
}

Atualizando dados

fun atualizarUsuario(id: Int, nome: String) {
    val db = writableDatabase

    val values = ContentValues().apply {
        put("nome", nome)
    }

    db.update("usuario", values, "id = ?", arrayOf(id.toString()))
}

Removendo dados

fun removerUsuario(id: Int) {
    val db = writableDatabase
    db.delete("usuario", "id = ?", arrayOf(id.toString()))
}

Problemas comuns com SQLite direto

Apesar de poderoso, usar SQLite diretamente tem vários pontos de atenção.

Código verboso

Você precisa escrever muito código para tarefas simples.

Risco de erro manual

Strings SQL espalhadas aumentam a chance de bugs.

Gerenciamento de cursor

Esquecer de fechar cursor pode gerar vazamentos.

Falta de segurança de tipo

Tudo é tratado como String, Int, etc., sem validação forte.


Boas práticas

Centralizar acesso ao banco

Evite espalhar lógica SQL pelo projeto.

Usar camada de repositório

Separe acesso a dados da regra de negócio.

Fechar recursos corretamente

Sempre feche cursor e conexões.

Versionar corretamente

Nunca ignore o método onUpgrade.


Alternativa moderna: Room

Hoje, o uso direto do SQLite é cada vez mais raro em projetos modernos.

A recomendação oficial é utilizar o Room, que abstrai o SQLite e traz benefícios importantes:

  • menos código

  • validação em tempo de compilação

  • integração com coroutines e Flow

  • maior segurança de tipo


Quando ainda usar SQLite direto?

Mesmo com Room, ainda há cenários onde SQLite direto faz sentido:

  • aplicações muito simples

  • controle total sobre SQL

  • otimizações específicas de performance

  • aprendizado da base relacional


Conclusão

O SQLite continua sendo um dos pilares do armazenamento local no Android. Entender como ele funciona é fundamental para qualquer desenvolvedor, mesmo que você utilize abstrações como Room no dia a dia.

Ele oferece poder e flexibilidade, mas exige mais cuidado e disciplina no uso.