¿Atrapaste un NetworkOnMainThreadException en 2025? Guía completa para solucionarlo en Java

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Una mañana que comienza con NetworkOnMainThreadException

\n\n

Estás escribiendo una aplicación en Android. Todo va perfectamente hasta que decides hacer una simple solicitud HTTP en un botón. Presionas "Actualizar" — y la aplicación se cae con un stack rojo. ¿Te suena familiar? android.os.NetworkOnMainThreadException es el error clásico que todo desarrollador Android ha visto al menos una vez en la vida. En 2025, sigue vigente, y los principiantes continúan cayendo en la misma trampa.

\n\n

En este artículo, analizaremos por qué ocurre NetworkOnMainThreadException, cómo solucionarlo en Java, y qué enfoques se consideran las mejores prácticas en 2025. Obtendrás soluciones listas con código que puedes insertar directamente en tu proyecto.

\n\n

¿Por qué ocurre NetworkOnMainThreadException?

\n\n

Android no es solo Java. Es un sistema con reglas estrictas. Una de ellas: no realices operaciones de red en el hilo principal (UI). El hilo principal se encarga de dibujar la interfaz y procesar los toques. Si se bloquea aunque sea por un segundo, el usuario verá "lag", y si se bloquea por cinco segundos, el sistema mostrará el diálogo "La aplicación no responde" (ANR).

\n\n

A partir de Android 3.0 (Honeycomb), Google añadió una protección: cualquier llamada de red en el hilo principal lanza android.os.NetworkOnMainThreadException. La excepción dice: "¡Oye, estás haciendo algo peligroso para la experiencia de usuario!".

\n\n

En 2025, esta regla no ha desaparecido. Incluso si usas bibliotecas modernas (Retrofit, OkHttp), igual estás obligado a ejecutarlas en un hilo en segundo plano. La excepción no es un error, sino una característica de seguridad.

\n\n

Top 5 formas de solucionar el error (Java, 2025)

\n\n

Veremos cinco enfoques, desde los obsoletos hasta los modernos. Elige el que se adapte a tu proyecto.

\n\n

1. AsyncTask clásico (legado, pero funcional)

\n\n

AsyncTask fue el estándar hace unos 10 años. En 2025 no se recomienda su uso (está deprecado en API 30+), pero en proyectos antiguos aún puedes encontrarlo.

\n\n
private class MyNetworkTask extends AsyncTask<String, Void, String> {\n    @Override\n    protected String doInBackground(String... params) {\n        // Este ya es un hilo en 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        // Este ya es el hilo UI\n        textView.setText(result);\n    }\n}\n\n// Ejecución:\nnew MyNetworkTask().execute("https://api.example.com/data");
\n\n

Desventajas: AsyncTask es difícil de probar, no es conveniente para cadenas de solicitudes y, en caso de rotación de pantalla, puede provocar fugas de memoria. Úsalo solo si el proyecto está escrito en Java 7-8.

\n\n

2. Java Thread + Handler (enfoque puro)

\n\n

La forma más sencilla es crear un hilo separado y devolver el resultado a la UI a través de Handler.

\n\n
private Handler mainHandler = new Handler(Looper.getMainLooper());\n\nprivate void fetchDataInBackground() {\n    new Thread(new Runnable() {\n        @Override\n        public void run() {\n            // Hilo en segundo plano\n            final String result = performNetworkCall();\n            \n            // Regresamos al hilo 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                

Blogs

Book Recommendations