Android:如何通过对话框取消文件下载并删除文件
解决Android下载任务取消后无法终止进程及删除文件的问题
我看了你的代码,问题主要出在没有在下载过程中检查任务是否被取消,以及取消后没有清理已下载的文件。下面一步步帮你修复:
问题分析
- 你调用了
DownloadingTask.this.cancel(true),但doInBackground里没有检查isCancelled(),所以下载循环会一直跑直到完成。 - 取消任务后没有删除已经下载了一部分的文件,导致残留垃圾。
- 用
runOnUiThread更新进度不是AsyncTask的标准用法,应该用onProgressUpdate方法。 - 上下文引用有点问题,比如
bookejtemaeat.this在独立的DownloadTask类里可能导致内存泄漏,应该用传入的context。
修改后的完整代码
public class DownloadTask { private static final String TAG = "Download Task"; private Context context; private String downloadUrl = "", downloadFileName = ""; private ProgressDialog progressDialog; private DownloadingTask downloadingTask; private File outputFile; // 把outputFile提升为成员变量,方便取消时删除 public DownloadTask(Context context, String downloadUrl) { this.context = context; this.downloadUrl = downloadUrl; downloadFileName = downloadUrl.substring(downloadUrl.lastIndexOf('/'), downloadUrl.length()); Log.e(TAG, downloadFileName); // 初始化并启动下载任务 downloadingTask = new DownloadingTask(); downloadingTask.execute(); } private class DownloadingTask extends AsyncTask<Void, Integer, Void> { File apkStorage = null; @Override protected void onPreExecute() { super.onPreExecute(); progressDialog = new ProgressDialog(context); // 替换成传入的context,避免内存泄漏 progressDialog.setMessage("يتم تحميل الملف مرة واحدة يرجى الانتظار ......"); progressDialog.setIndeterminate(false); // 因为用了水平进度条,设为false更合理 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setCancelable(false); progressDialog.setProgress(0); progressDialog.setCanceledOnTouchOutside(false); progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { downloadingTask.cancel(true); // 触发任务取消 dialog.dismiss(); } }); progressDialog.show(); } @Override protected Void doInBackground(Void... arg0) { try { URL url = new URL(downloadUrl); HttpURLConnection c = (HttpURLConnection) url.openConnection(); c.setRequestMethod("GET"); c.connect(); final int fileLength = c.getContentLength(); Log.e(TAG, "fileLength " + fileLength); if (c.getResponseCode() != HttpURLConnection.HTTP_OK) { Log.e(TAG, "Server returned HTTP " + c.getResponseCode() + " " + c.getResponseMessage()); return null; } // 检查SD卡或使用私有目录 if (new CheckForSDCard().isSDCardPresent()) { apkStorage = context.getApplicationContext().getDir("NKDROID FILES", Context.MODE_PRIVATE); } else { // 这里可以考虑使用内部存储,而不是只弹Toast apkStorage = context.getFilesDir(); Toast.makeText(context, "Tidak ada SD Card, menggunakan penyimpanan internal.", Toast.LENGTH_SHORT).show(); } if (!apkStorage.exists()) { apkStorage.mkdir(); Log.e(TAG, "Directory Created."); } outputFile = new File(apkStorage, downloadFileName); if (!outputFile.exists()) { outputFile.createNewFile(); Log.e(TAG, "File Created"); } FileOutputStream fos = new FileOutputStream(outputFile); InputStream is = c.getInputStream(); byte[] buffer = new byte[1024]; int len1; long total = 0; while ((len1 = is.read(buffer)) != -1) { // 每次循环前检查任务是否被取消,如果是就中断 if (isCancelled()) { break; } total += len1; publishProgress((int) (total * 100 / fileLength)); // 用publishProgress触发进度更新 fos.write(buffer, 0, len1); } // 关闭流,不管是否取消都要执行 fos.close(); is.close(); c.disconnect(); // 断开连接 } catch (Exception e) { e.printStackTrace(); outputFile = null; Log.e(TAG, "Download Error Exception " + e.getMessage()); } return null; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); // 在主线程更新进度,这是AsyncTask的标准方式 progressDialog.setProgress(values[0]); } @Override protected void onCancelled() { super.onCancelled(); // 任务被取消时,删除已下载的文件 if (outputFile != null && outputFile.exists()) { boolean deleted = outputFile.delete(); Log.e(TAG, "Canceled, deleted partial file: " + deleted); } // 可以在这里做一些其他清理工作 } } }
关键改动说明
- 新增
onCancelled方法:当任务被取消时,这个方法会被调用,在这里删除临时文件。 doInBackground中检查isCancelled():每次读取数据前都判断,如果任务已取消就跳出循环,终止下载。- 进度更新移到
onProgressUpdate:移除了runOnUiThread,改用AsyncTask自带的进度更新机制,更规范且避免线程问题。 - 提升
outputFile为成员变量:这样在onCancelled里能直接访问到要删除的文件。 - 修复上下文引用:把
bookejtemaeat.this换成context,避免内存泄漏,同时在SD卡不存在时 fallback 到内部存储,增强鲁棒性。
这样修改后,点击取消按钮就能立即终止下载进程,并删除已经下载的部分文件了。
内容的提问来源于stack exchange,提问作者ahmmed
相关产品推荐
相关产品推荐

