Descarga de archivos en Android: de la idea al código funcional
\n\nTodo desarrollador de Android, tarde o temprano, se enfrenta a la tarea de descargar un archivo desde la red. Puede ser una actualización de la aplicación, la descarga de una imagen, un documento PDF o una pista de música. Pero simplemente descargar el archivo es solo la mitad del trabajo. El usuario debe ver que el proceso está en marcha: cuánto se ha descargado, cuánto falta y que la aplicación no se ha congelado.
\n\nEn este artículo, analizaremos una pregunta clásica de Stack Overflow que ha acumulado miles de visitas: cómo descargar un archivo en Android y mostrar el progreso en un cuadro de diálogo. Escribiremos el código en Java, utilizando AsyncTask y ProgressDialog (aunque en proyectos modernos a menudo se reemplazan con corrutinas o RxJava, comprender los clásicos es la base que sigue siendo fundamental).
¿Listos? ¡Vamos allá!
\n\n¿Por qué es tan difícil? Tres obstáculos de la descarga en Android
\n\nA primera vista, la tarea es simple: abrir una conexión, leer el flujo de bytes y escribir en un archivo. Pero en la práctica, los desarrolladores tropiezan con tres cosas:
\n\n- \n
- El hilo de la UI se bloquea — si inicias la descarga en el hilo principal, la aplicación se «congelará» y Android mostrará el diálogo «La aplicación no responde». \n
- El progreso no se actualiza — incluso si cuentas los bytes, no puedes simplemente cambiar la UI desde un hilo en segundo plano. \n
- La configuración cambia — el usuario gira la pantalla y tu
Activityse recrea. El diálogo desaparece y la descarga continúa sin destino. \n
Resolveremos los tres problemas. Empezaremos con la arquitectura y luego escribiremos el código.
\n\nElegimos las herramientas: AsyncTask y ProgressDialog
\n\nCon fines educativos, utilizaremos el enfoque clásico:
\n- \n
AsyncTask— para realizar trabajo en segundo plano y publicar el progreso. \n ProgressDialog— para mostrar los porcentajes. \n HttpURLConnection— para la solicitud HTTP (sigue vivo, aunque está obsoleto). \n
Importante: En proyectos reales, hoy en día se usa más a menudo DownloadManager, WorkManager o bibliotecas como Retrofit + OkHttp. Pero entender cómo funciona la descarga «a mano» es un must-have para cualquier desarrollador.
Código completo: descarga de archivos con ProgressDialog
\n\nA continuación se presenta una clase lista para usar para la descarga. El código está comentado en español para que entiendas de inmediato lo que sucede.
\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.os.AsyncTask;\nimport android.os.Environment;\nimport android.widget.Toast;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic class DownloadFileTask extends AsyncTask<String, Integer, String> {\n\n private Context context;\n private ProgressDialog progressDialog;\n\n public DownloadFileTask(Context context) {\n this.context = context;\n }\n\n @Override\n protected void onPreExecute() {\n super.onPreExecute();\n // Creamos y mostramos el diálogo de progreso\n progressDialog = new ProgressDialog(context);\n progressDialog.setTitle("Descarga de archivo");\n progressDialog.setMessage("Descargando...");\n progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);\n progressDialog.setCancelable(false); // No permitimos cerrarlo accidentalmente\n progressDialog.show();\n }\n\n @Override\n protected String doInBackground(String... params) {\n String fileUrl = params[0];\n String fileName = "downloaded_file.pdf"; // Se puede pasar como segundo parámetro\n InputStream inputStream = null;\n FileOutputStream outputStream = null;\n\n try {\n // 1. Establecemos la conexión\n URL url = new URL(fileUrl);\n HttpURLConnection connec