Manhã que começa com NetworkOnMainThreadException
\n\nVocê está escrevendo um aplicativo Android. Tudo está indo bem, até que você decide fazer uma simples requisição HTTP em um botão. Você clica em "Atualizar" — e o aplicativo trava com um stack trace vermelho. Familiar? android.os.NetworkOnMainThreadException é o erro clássico que todo desenvolvedor Android já viu pelo menos uma vez na vida. Em 2025, ele ainda está vivo, e os iniciantes continuam pisando na mesma casca de banana.
\n\nNeste artigo, vamos explicar por que o NetworkOnMainThreadException ocorre, como corrigi-lo em Java e quais abordagens são consideradas melhores práticas em 2025. Você receberá soluções prontas com código que podem ser inseridas diretamente no seu projeto.
\n\nPor que ocorre o NetworkOnMainThreadException?
\n\nAndroid não é apenas Java. É um sistema com regras rígidas. Uma delas: não execute operações de rede na thread principal (UI). A thread principal é responsável por renderizar a interface e processar toques. Se ela for bloqueada por apenas um segundo, o usuário verá "lentidão"; se por cinco segundos, o sistema exibirá o diálogo "O aplicativo não está respondendo" (ANR).
\n\nA partir do Android 3.0 (Honeycomb), o Google adicionou uma proteção: qualquer chamada de rede na thread principal lança android.os.NetworkOnMainThreadException. A exceção diz: "Ei, você está fazendo algo perigoso para a experiência do usuário!".
Em 2025, essa regra não mudou. Mesmo que você use bibliotecas modernas (Retrofit, OkHttp), ainda é obrigado a executá-las em uma thread em segundo plano. A exceção não é um bug, mas um recurso de segurança.
\n\nTop 5 maneiras de corrigir o erro (Java, 2025)
\n\nVamos analisar cinco abordagens — desde as obsoletas até as modernas. Escolha a que melhor se adequa ao seu projeto.
\n\n1. AsyncTask clássico (legado, mas funcional)
\n\nAsyncTask foi o padrão há cerca de 10 anos. Em 2025, não é recomendado usá-lo (está deprecated na API 30+), mas você ainda pode encontrá-lo em projetos antigos.
\n\nprivate class MyNetworkTask extends AsyncTask<String, Void, String> {\n @Override\n protected String doInBackground(String... params) {\n // Esta já é uma thread em segundo plano\n try {\n URL url = new URL(params[0]);\n HttpURLConnection connection = (HttpURLConnection) url.openConnection();\n BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));\n StringBuilder result = new StringBuilder();\n String line;\n while ((line = reader.readLine()) != null) {\n result.append(line);\n }\n return result.toString();\n } catch (Exception e) {\n return "Error: " + e.getMessage();\n }\n }\n\n @Override\n protected void onPostExecute(String result) {\n // Esta já é a thread da UI\n textView.setText(result);\n }\n}\n\n// Execução:\nnew MyNetworkTask().execute("https://api.example.com/data");\n\nDesvantagens: AsyncTask é difícil de testar, inconveniente para encadeamento de requisições e pode vazar memória em caso de rotação de tela. Use apenas se o projeto foi escrito em Java 7-8.
\n\n2. Java Thread + Handler (abordagem pura)
\n\nA maneira mais simples é criar uma thread separada e retornar o resultado para a UI através de um Handler.
\n\nprivate Handler mainHandler = new Handler(Looper.getMainLooper());\n\nprivate void fetchDataInBackground() {\n new Thread(new Runnable() {\n @Override\n public void run() {\n // Thread em segundo plano\n final String result = performNetworkCall();\n \n // Retornando para a thread da UI\n mainHandler.post(new Runnable() {\n @Override\n public void run() {\n textView.setText(result);\n }\n });\n }\n }).start();\n}\n\nprivate String performN