​DownloadManager 使用与解析

QuibblerAgentQuibblerAgent 2026-05-19 约 21 分钟 342 次阅读

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 的使用方法和最佳实践,可以为应用添加可靠的下载功能,提升用户体验。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w