在安卓上下载文件:从想法到可运行的代码
\n\n每一位安卓开发者迟早都会遇到从网络下载文件的任务。这可能是应用更新、下载图片、PDF文档或音乐文件。但仅仅下载文件只是成功了一半。用户需要看到过程正在进展:已下载多少、还剩多少、以及应用没有卡死。
\n\n在本文中,我们将解析一个来自 Stack Overflow 的经典问题,该问题获得了数千次浏览:如何在安卓上下载文件并在对话框中显示进度。我们将使用 Java 编写代码,利用 AsyncTask 和 ProgressDialog(尽管在现代项目中它们常被协程或RxJava取代,但理解经典方法仍是不可或缺的基础)。
准备好了吗?我们开始吧!
\n\n为什么这么难?安卓下载的三个陷阱
\n\n乍一看,任务很简单:打开连接、读取字节流、写入文件。但在实践中,开发者常常在三个方面遇到问题:
\n\n- \n
- UI线程被阻塞 — 如果在主线程中启动下载,应用会“冻结”,安卓会显示“应用无响应”对话框。 \n
- 进度不更新 — 即使你计算了字节数,也不能直接从后台线程更改UI。 \n
- 配置发生变化 — 用户旋转屏幕,你的
Activity被重建。对话框消失,下载也失去了目标。 \n
我们将解决所有这三个问题。先从架构开始,然后编写代码。
\n\n选择工具:AsyncTask 和 ProgressDialog
\n\n出于教学目的,我们使用经典方法:
\n- \n
AsyncTask— 用于执行后台工作并发布进度。 \n ProgressDialog— 用于显示百分比。 \n HttpURLConnection— 用于HTTP请求(它仍然可用,尽管已过时)。 \n
重要提示: 在实际项目中,如今更常使用 DownloadManager、WorkManager 或诸如 Retrofit + OkHttp 之类的库。但理解“手动”下载的工作原理是任何开发者的必备技能。
完整代码:使用ProgressDialog下载文件
\n\n下面是一个现成的下载类。代码附有中文注释,以便您立即理解正在发生的事情。
\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 // 创建并显示进度对话框\n progressDialog = new ProgressDialog(context);\n progressDialog.setTitle("文件下载");\n progressDialog.setMessage("正在下载...");\n progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);\n progressDialog.setCancelable(false); // 防止意外关闭\n progressDialog.show();\n }\n\n @Override\n protected String doInBackground(String... params) {\n String fileUrl = params[0];\n String fileName = "downloaded_file.pdf"; // 可以作为第二个参数传递\n InputStream inputStream = null;\n FileOutputStream outputStream = null;\n\n try {\n // 1. 建立连接\n URL url = new URL(fileUrl);\n HttpURLConnection connec