Por que o Room reclama da main thread? Analisando o erro e 3 maneiras de resolvê-lo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que um "SELECT simples" se torna uma dor de cabeça

\n\n

Você está escrevendo seu primeiro aplicativo Android com Room e Kotlin. Tudo vai bem, até chegar a hora de ler dados do banco. Você escreve algo como:

\n\n
val user = userDao.getUserById(42)\ntextView.text = user.name
\n\n

Você executa — e o aplicativo trava com a exceção:

\n\n
java.lang.IllegalStateException: Cannot access database on the main thread\nsince it may potentially lock the UI for a long period of time.
\n\n

Familiar? Esta pergunta no Stack Overflow acumulou milhares de visualizações e centenas de comentários. O erro assusta iniciantes, mas na verdade não é um bug — é uma proteção contra o usuário descuidado. O Room (como qualquer ORM competente) não permite que você bloqueie acidentalmente a interface do usuário.

\n\n

Neste artigo, vamos analisar por que isso acontece e como executar corretamente consultas SELECT no Android Room com Kotlin. Você conhecerá três abordagens comprovadas: LiveData, Coroutines e RxJava. Vamos lá!

\n\n

Resumindo: por que o Room bloqueia a main thread?

\n\n

O Android é um sistema single-thread por padrão. Toda a interface do usuário (UI) roda na main thread (thread principal). Se você começar a ler o banco de dados nesta thread, a interface congelará até que a consulta termine. Com grandes volumes de dados, isso pode levar segundos — o usuário verá um aplicativo "travado".

\n\n

O Room é cauteloso: ele proíbe qualquer operação longa (leitura, gravação) na thread principal. A exceção é se você permitir explicitamente através de .allowMainThreadQueries() ao construir o banco. Mas não faça isso — é um antipadrão.

\n\n

Veja como é o problema típico:

\n\n
// DAO\n@Dao\ninterface UserDao {\n    @Query("SELECT * FROM users WHERE id = :userId")\n    suspend fun getUserById(userId: Int): User  // suspend — já é uma dica!\n}\n\n// Activity\nclass MainActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        // ❌ Erro!\n        val user = database.userDao().getUserById(42)\n    }\n}
\n\n

Mesmo se você tornar a função suspend, mas chamá-la sem uma coroutine — o Room ainda lançará a exceção. Vamos corrigir!

\n\n

Abordagem 1: LiveData — simples e reativo

\n\n

A maneira mais simples é retornar LiveData do DAO. O próprio Room gerencia a thread: a consulta é executada em segundo plano e o resultado chega na UI.

\n\n

Passo 1. Alterar o DAO

\n\n
@Dao\ninterface UserDao {\n    @Query("SELECT * FROM users WHERE id = :userId")\n    fun getUserById(userId: Int): LiveData<User>\n}
\n\n

Passo 2. Inscrever-se na Activity/Fragment

\n\n
class MainActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        database.userDao().getUserById(42).observe(this) { user ->\n            textView.text = user.name\n        }\n    }\n}
\n\n

Vantagens: mínimo de código, cancelamento automático da inscrição quando a Activity é destruída, reatividade — os dados são atualizados automaticamente quando a tabela é alterada.

\n\n

Desvantagens: LiveData está vinculada ao ciclo de vida, não é fácil combinar com outras fontes de dados (rede, SharedPreferences).

\n\n

Abordagem 2: Coroutines — o caminho moderno do Kotlin

\n\n

Se você usa Kotlin Coroutines (e deveria), esta é a maneira mais elegante. A função é marcada como suspend e a chamada é envolvida em uma coroutine com o Dispatchers.IO correto.

\n\n

Passo 1. DAO com suspend

\n\n
@Dao\ninterface UserDao {\n    @Query("SELECT * FROM users WHERE id = :userId")\n    suspend fun getUserById(userId: Int): User\n}
\n\n

Passo 2. Chamada a partir da ViewModel (recomendado)

\n\n
class MainVi                

Blogs

Book Recommendations