DownloadManager 使用与解析
1、DownloadManager 概述
1.1、什么是 DownloadManager
DownloadManager 是 Android 系统提供的一个系统服务,用于处理长时间运行的 HTTP 下载。它可以在后台进行下载,处理 HTTP 交互,并在失败后或跨连接更改和系统重启后重试下载。
1.2、DownloadManager 的特点
- 处理后台下载,不阻塞主线程
- 自动处理网络变化和系统重启
- 提供下载进度和状态跟踪
- 支持大文件下载
- 集成系统通知栏
- 支持断点续传
1.3、DownloadManager 的适用场景
- 应用更新
- 大文件下载
- 后台资源下载
- 内容缓存
- 固件升级
1.4、权限要求
使用 DownloadManager 需要在 AndroidManifest.xml 中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />对于 Android 6.0 及以上版本,还需要存储权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />2、DownloadManager 基本使用
2.1、获取 DownloadManager 实例
DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);2.2、创建下载请求
DownloadManager.Request request = new DownloadManager.Request(Uri.parse("https://example.com/file.zip"));2.3、配置下载请求
// 设置通知标题
request.setTitle("下载文件");
// 设置通知描述
request.setDescription("正在下载文件,请稍候...");
// 设置通知可见性
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
// 设置下载目录和文件名
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "file.zip");
// 设置允许的网络类型
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
// 设置是否允许漫游
request.setAllowedOverRoaming(false);
// 设置是否允许计费网络
request.setAllowedOverMetered(true);2.4、执行下载
long downloadId = downloadManager.enqueue(request);2.5、查询下载状态
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
Cursor cursor = downloadManager.query(query);
if (cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
long bytesDownloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
long totalSize = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
switch (status) {
case DownloadManager.STATUS_PENDING:
// 等待中
break;
case DownloadManager.STATUS_RUNNING:
// 下载中
int progress = (int) (bytesDownloaded * 100 / totalSize);
break;
case DownloadManager.STATUS_PAUSED:
// 暂停
break;
case DownloadManager.STATUS_SUCCESSFUL:
// 下载成功
String localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
break;
case DownloadManager.STATUS_FAILED:
// 下载失败
int reason = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON));
break;
}
}
cursor.close();2.6、取消下载
downloadManager.remove(downloadId);3、DownloadManager 高级功能
3.1、监听下载完成
// 注册广播接收器
private BroadcastReceiver downloadCompleteReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
// 处理下载完成
handleDownloadComplete(downloadId);
}
};
// 注册广播
registerReceiver(downloadCompleteReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
// 处理下载完成
private void handleDownloadComplete(long downloadId) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
Cursor cursor = downloadManager.query(query);
if (cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status == DownloadManager.STATUS_SUCCESSFUL) {
String localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
// 处理下载完成的文件
processDownloadedFile(Uri.parse(localUri));
}
}
cursor.close();
}3.2、监听通知点击
// 注册广播接收器
private BroadcastReceiver notificationClickedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String extraId = DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS;
long[] ids = intent.getLongArrayExtra(extraId);
// 处理通知点击
handleNotificationClicked(ids);
}
};
// 注册广播
registerReceiver(notificationClickedReceiver, new IntentFilter(DownloadManager.ACTION_NOTIFICATION_CLICKED));3.3、批量下载管理
// 存储下载 ID
private List<Long> downloadIds = new ArrayList<>();
// 添加下载
public long addDownload(String url, String fileName) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setTitle(fileName);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
long downloadId = downloadManager.enqueue(request);
downloadIds.add(downloadId);
return downloadId;
}
// 取消所有下载
public void cancelAllDownloads() {
for (long id : downloadIds) {
downloadManager.remove(id);
}
downloadIds.clear();
}3.4、设置下载优先级
// 设置下载优先级(0-9,越高优先级越高)
request.setPriority(DownloadManager.Request.PRIORITY_HIGH);3.5、设置 MIME 类型
// 设置 MIME 类型
request.setMimeType("application/zip");3.6、设置可见性
// 设置通知可见性
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE); // 始终显示
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // 完成后显示
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION); // 仅完成时显示
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); // 不显示4、DownloadManager 最佳实践
4.1、权限处理
// 检查并请求存储权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION);
}4.2、错误处理
private void handleDownloadError(int reason) {
switch (reason) {
case DownloadManager.ERROR_CANNOT_RESUME:
// 无法恢复下载
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
// 未找到外部存储设备
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
// 文件已存在
break;
case DownloadManager.ERROR_FILE_ERROR:
// 文件错误
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
// HTTP 数据错误
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
// 空间不足
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
// 重定向过多
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
// 未处理的 HTTP 代码
break;
case DownloadManager.ERROR_UNKNOWN:
// 未知错误
break;
}
}4.3、性能优化
- 避免在主线程中执行查询操作
- 合理设置下载优先级
- 及时清理不再需要的下载记录
- 批量处理多个下载请求
4.4、存储路径选择
// 应用私有目录(推荐)
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "file.zip");
// 公共下载目录
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "file.zip");
// 内部存储
request.setDestinationUri(Uri.fromFile(new File(getFilesDir(), "file.zip")));4.5、网络策略
// 仅在 WiFi 下下载
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
// 在 WiFi 和移动网络下都可以下载
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
// 允许在漫游时下载
request.setAllowedOverRoaming(true);
// 允许在计费网络下下载
request.setAllowedOverMetered(true);4.6、安全性
- 验证下载文件的完整性
- 使用 HTTPS 链接
- 检查文件 MIME 类型
- 避免下载可疑文件
5、DownloadManager 常见问题与解决方案
5.1、下载失败
- 检查网络连接
- 检查存储权限
- 检查存储空间
- 检查 URL 是否有效
- 检查服务器状态
5.2、下载速度慢
- 检查网络质量
- 避免同时下载多个大文件
- 选择合适的网络类型
- 考虑使用分块下载
5.3、通知不显示
- 检查通知可见性设置
- 检查应用通知权限
- 检查系统通知设置
5.4、文件找不到
- 检查存储路径权限
- 检查文件是否被系统清理
- 检查下载状态是否成功
5.5、重复下载
- 检查文件是否已存在
- 实现下载队列管理
- 避免重复调用 enqueue 方法
DownloadManager 是 Android 系统提供的一个强大的下载管理服务,它可以在后台处理长时间运行的 HTTP 下载,自动处理网络变化和系统重启。通过合理配置和使用 DownloadManager,可以实现高效、可靠的文件下载功能。
在实际开发中,需要注意以下几点:
- 正确处理权限
- 合理配置下载请求
- 监听下载状态和完成事件
- 优化性能和存储使用
- 处理各种错误情况
通过掌握 DownloadManager 的使用方法和最佳实践,可以为应用添加可靠的下载功能,提升用户体验。

