android.os.NetworkOnMainThreadException significa que um aplicativo Android tentou executar uma operação de rede na thread principal da interface. O Android lança essa exceção em aplicativos destinados ao SDK Honeycomb/API de nível 11 ou posterior. A primeira medida mais segura não é suprimir a exceção: inspecione o caminho da chamada que falhou, identifique a primeira operação de rede bloqueante pertencente ao aplicativo e determine se a API cliente envolvida é síncrona ou já pode ser chamada com segurança a partir da thread principal.
O que significa android.os.NetworkOnMainThreadException
A exceção exata é android.os.NetworkOnMainThreadException. Segundo a referência de NetworkOnMainThreadException do Android, ela é lançada quando um aplicativo tenta executar uma operação de rede na thread principal. Ela foi adicionada no nível 11 da API e é lançada em aplicativos destinados ao SDK Honeycomb ou posterior.
A operação que aciona a exceção pode ser uma conexão de URL bloqueante, URL.openStream(), acesso a sockets, resolução de nomes ou uma chamada síncrona de cliente. Código com corrotinas também pode acionar a exceção ao executar E/S bloqueante sem mudar para um dispatcher de segundo plano adequado. O fato de uma função ser marcada como suspend não transfere, por si só, o trabalho para fora da thread principal.
O bloqueio da thread principal impede o processamento de eventos da interface enquanto a operação está em execução, criando risco de falta de resposta e de o aplicativo não responder. Aplicativos destinados a níveis anteriores do SDK não estavam sujeitos a essa exceção da mesma forma, mas isso não torna seguro nem recomendável executar operações de rede na thread principal.
Localize a chamada de rede bloqueante no caminho da falha
Use o stack trace da falha reproduzível para localizar a operação síncrona antes de alterar o modelo de execução. Os nomes e a ordem exata dos frames variam conforme o aplicativo e a biblioteca de rede, portanto essa etapa exige confirmação específica no projeto.
- Reproduza a operação que informa
android.os.NetworkOnMainThreadExceptione preserve o stack trace completo. - Leia o stack trace a partir da exceção em direção aos frames do aplicativo. Procure o primeiro frame pertencente ao projeto que leve a uma conexão de URL,
URL.openStream(), acesso a sockets, resolução de nomes ou uma chamada síncrona de cliente. - Consulte a documentação da biblioteca envolvida para determinar se o método é bloqueante, baseado em callback ou uma API suspensa documentada como segura para chamada a partir da thread principal.
- Rastreie o contexto de execução do chamador. Caminhos iniciados por uma atividade, um fragmento, um callback de composable ou
viewModelScopenormalmente começam na thread principal, mas o caminho real do projeto precisa ser verificado. - Escolha uma das correções correspondentes abaixo, em vez de envolver toda API de rede em outro mecanismo de execução.
O stack trace pode mostrar StrictMode$AndroidBlockGuardPolicy.onNetwork acima de um frame pertencente ao aplicativo. Esse é um padrão de diagnóstico comum, não uma sequência universal de frames. O frame relevante é a chamada do projeto que iniciou a operação bloqueante.
Use o StrictMode somente quando for necessário um diagnóstico adicional durante a depuração
Quando se aplica: use o StrictMode durante testes locais quando a falha existente não revelar claramente um acesso acidental à rede na thread principal.
Pré-requisitos: use uma versão de depuração ou um ambiente de teste local e planeje remover ou flexibilizar a política de diagnóstico após a verificação.
- Ative o StrictMode na versão de depuração.
- Acione o fluxo que apresenta a falha.
- Inspecione a violação informada e identifique a primeira chamada de rede bloqueante pertencente ao aplicativo.
- Corrija a thread responsável pela chamada em vez de suprimir a violação.
Resultado esperado: o diagnóstico identifica um caminho pertencente ao aplicativo que pode ser atribuído à API assíncrona, ao dispatcher ou à correção com Executor adequada.
Risco e reversão: o risco é baixo e não há risco esperado de perda de dados. Desative a política exclusiva de depuração depois de verificar a correção. Não use permitAll() nem permitNetwork() como correção em produção.
Escolha a correção correspondente à API de rede
Use o caminho aplicável menos invasivo. Primeiro, determine se o cliente já executa as operações de forma assíncrona. Adicione um dispatcher ou Executor somente quando a operação subjacente for bloqueante.
Correção 1: use diretamente uma API cliente que já seja assíncrona ou segura para a thread principal
Quando se aplica: use este caminho quando a documentação da biblioteca informar que a API de callback ou suspensa já executa o trabalho em segundo plano e pode ser chamada com segurança a partir de código na thread principal.
Pré-requisitos: confirme o comportamento na documentação da biblioteca cliente. Não presuma que todo método marcado como suspend seja seguro para a thread principal.
- Prefira a API de callback assíncrona ou a API suspensa segura para a thread principal documentada pela biblioteca.
- Chame essa API a partir de código seguro para a thread principal.
- Não adicione um wrapper redundante de
withContext(Dispatchers.IO)a uma API já documentada como segura para a thread principal. - Retome o trabalho da interface na thread principal depois que a operação for concluída.
Resultado esperado: a biblioteca executa a operação de rede sem bloquear a thread principal do Android, enquanto o chamador processa o resultado no contexto correto da interface.
Risco e reversão: o risco é baixo e não há risco esperado de perda de dados. Se a documentação ou os testes mostrarem que a API não é realmente segura para a thread principal, deixe de usar este caminho e transfira a camada bloqueante para fora de Main. A documentação sobre corrotinas do Kotlin no Android diferencia o código bloqueante que precisa de Dispatchers.IO das APIs de rede que já oferecem comportamento suspenso seguro para a thread principal.
Correção 2: mova operações de rede bloqueantes em Kotlin para withContext(Dispatchers.IO)
Quando se aplica: use este caminho para uma função suspensa do Kotlin que invoque diretamente código bloqueante de rede ou resolução de nomes.
Pré-requisitos: você precisa controlar a função suspensa ou a camada do repositório, e a operação subjacente precisa ser bloqueante, em vez de já ser segura para a thread principal.
- Mantenha o chamador em Main quando ele for responsável pelo estado da interface.
- Envolva somente o bloco de rede bloqueante em
withContext(Dispatchers.IO)ou use o dispatcher de E/S injetado pelo projeto. - Retorne ao chamador apenas o resultado da operação.
- Atualize o estado da interface depois que a chamada suspensa terminar e a execução voltar para Main.
Resultado esperado: a E/S bloqueante é executada no dispatcher de E/S, enquanto o estado da interface permanece sob responsabilidade da thread principal.
Risco e reversão: o risco é baixo e não há risco esperado de perda de dados. Remova a mudança de dispatcher somente se for confirmado que a biblioteca oferece uma API suspensa segura para a thread principal. As práticas recomendadas para corrotinas no Android exigem que funções suspensas que possam ser chamadas a partir de Main sejam seguras para a thread principal e observam que viewModelScope normalmente começa em Dispatchers.Main.
Correção 3: use um Executor Java e retorne o resultado para Main
Quando se aplica: use este caminho para código Java que execute diretamente E/S de rede bloqueante.
Pré-requisitos: o aplicativo precisa ter um Executor ou pool de threads em segundo plano e um caminho de callback na thread principal para atualizar a interface.
- Envie a tarefa de rede bloqueante ao Executor.
- Execute a chamada de rede dentro dessa tarefa em segundo plano, e não na thread principal.
- Envie o resultado de volta pelo caminho de callback da thread principal do aplicativo.
- Atualize as views somente por meio desse callback na thread principal.
Resultado esperado: a operação bloqueante é executada pelo Executor, e somente o trabalho de interface resultante retorna para Main.
Risco e reversão: o risco é baixo e não há risco esperado de perda de dados. Cancele a tarefa ou deixe de enviar novos trabalhos quando a interface que iniciou a operação não existir mais. Transferir a operação de rede para fora de Main não torna seguro atualizar views a partir da tarefa em segundo plano.
Gerencie o ciclo de vida e o trabalho persistente sem criar outro problema
Atribuir o trabalho à thread correta não torna uma solicitação automaticamente segura em relação ao ciclo de vida. Uma solicitação pode continuar depois que a atividade ou o fragmento for encerrado, retornar para uma interface obsoleta ou duplicar trabalho quando a ação inicial for repetida. As políticas de cancelamento, tratamento de destruição e solicitações duplicadas dependem da arquitetura do aplicativo e precisam ser verificadas no projeto de destino.
- Confirme o que acontece se a atividade ou o fragmento for destruído enquanto o trabalho ainda estiver ativo.
- Garanta que o trabalho em segundo plano não atualize views depois que a interface relacionada não existir mais.
- Verifique se ações repetidas podem enviar solicitações duplicadas.
- Cancele o trabalho ou deixe de aceitar o resultado quando o ciclo de vida responsável não precisar mais dele.
Use o WorkManager somente para trabalho persistente ou adiável
Quando se aplica: use o WorkManager quando a tarefa de rede puder ser adiada, for de longa duração ou precisar continuar após reinicializações do aplicativo. Ele não é o substituto padrão para toda solicitação imediata iniciada pela interface.
Pré-requisitos: a operação precisa ser adequada para execução como trabalho em segundo plano, e não como uma solicitação imediata vinculada à tela atual.
- Crie uma WorkRequest ou um Worker para a operação em segundo plano.
- Adicione restrições de rede se a tarefa precisar delas.
- Permita que o WorkManager execute a operação fora da thread da interface.
- Observe a conclusão e atualize a interface separadamente.
Resultado esperado: o trabalho persistente ou adiável é gerenciado independentemente da tela que o iniciou e não bloqueia a thread principal.
Risco e reversão: o risco é baixo e não há risco esperado de perda de dados. Cancele a WorkRequest quando a tarefa não for mais necessária. Se a solicitação exigir uma resposta imediata para a interface atual, use o caminho aplicável com API assíncrona, corrotina ou Executor.
Verifique se a exceção foi corrigida
- Reproduza o fluxo original que apresentava a falha depois de aplicar um caminho de correção adequado.
- Confirme que a operação bloqueante de rede ou resolução de nomes não é mais executada na thread principal.
- Confirme que as atualizações de views e do estado da interface ocorrem somente depois que o resultado retorna para Main.
- Teste o que acontece quando a atividade ou o fragmento que iniciou a operação é destruído antes da conclusão.
- Teste entradas repetidas para determinar se solicitações duplicadas são criadas ou controladas corretamente.
- Em uma versão de depuração, use o StrictMode para procurar outros acessos acidentais à rede na thread principal e depois restaure a política de depuração pretendida.
- Analise o stack trace resultante se outra exceção aparecer. Diagnostique a nova assinatura separadamente, em vez de tratá-la como outra ocorrência de
NetworkOnMainThreadException.
A correção de threading estará verificada quando o fluxo original deixar de executar trabalho de rede bloqueante em Main e todas as alterações relacionadas à interface continuarem ocorrendo em Main. Uma resposta bem-sucedida do endpoint, por si só, não comprova que o trabalho foi atribuído à thread correta, e remover essa exceção não garante que a solicitação de rede terá sucesso.
Erros e soluções alternativas que não correspondem a esta correção
| Mensagem ou abordagem | Por que é diferente |
|---|---|
UnknownHostException |
Essa é uma falha diferente, relacionada à resolução ou acessibilidade do host, e não comprova que o trabalho de rede foi executado em Main. |
SSLHandshakeException |
Essa é uma falha de TLS separada e exige um diagnóstico próprio. |
| Permissão INTERNET ausente | Esse é um problema de permissão ou configuração, não a causa que define NetworkOnMainThreadException. |
| Falha na política de tráfego não criptografado | Essa é uma restrição da política de segurança de rede sobre tráfego não criptografado, não uma violação por execução na thread principal. |
CalledFromWrongThreadException |
Essa exceção se refere ao acesso a uma view pela thread errada depois que o trabalho muda de contexto; não é a mesma exceção. |
permitAll() ou permitNetwork() |
Esses métodos flexibilizam a restrição de diagnóstico em vez de corrigir a responsabilidade pela operação bloqueante. |
| Orientações obsoletas sobre AsyncTask | AsyncTask está obsoleto e não é a correção moderna recomendada. |
Não comece investigando TLS, acessibilidade de DNS, permissões ou tráfego não criptografado quando a falha real for android.os.NetworkOnMainThreadException. Primeiro, atribua o trabalho à thread correta. Se a transferência de uma solicitação HTTP para fora de Main revelar uma falha separada de Cleartext HTTP traffic not permitted, diagnostique esse novo erro de forma independente.

