You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Android开发:如何正确使用DownloadManager的COLUMN_ID等列字段

嘿,我完全懂你的困惑——刚从C#转Android开发,碰到DownloadManager的这些COLUMN_*字段确实容易摸不着头脑!你现在看到Toast显示_idtotal_size是正常的,因为这些常量本质是DownloadManager内部数据库的列名称字符串,不是直接能拿到下载数据的字段。下面我给你掰明白怎么正确用它们:

先搞懂核心逻辑

DownloadManager.COLUMN_IDCOLUMN_TOTAL_SIZE_BYTES这些常量,是用来给ContentProvider查询做“索引标记”的——你得先拿到具体下载任务的ID,再用这些常量去查询数据库,才能获取到对应的实际数值(比如任务ID、总大小、已下载进度)。

第一步:保存下载任务的ID

当你调用manager.enqueue(request)时,这个方法会返回当前下载任务的唯一ID(Long类型),这是你后续查询的关键!你的原代码里没保存这个ID,所以根本没法关联到具体的下载任务。

修改你的下载方法,先把ID存下来:

fun download(url: String, name: String) {
    val request = DownloadManager.Request(Uri.parse(url))
        .setVisibleInDownloadsUi(true)
        .allowScanningByMediaScanner()
        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        // 建议用系统提供的目录常量,更适配不同版本
        .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "$name.pdf")

    val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    // 保存下载任务ID!这是核心
    val downloadId = manager.enqueue(request)

    // 现在可以用这个ID去查询下载数据了
    val downloadInfo = getDownloadDetails(downloadId)
    Toast.makeText(applicationContext, downloadInfo, Toast.LENGTH_SHORT).show()
}

第二步:用ID + COLUMN_*常量查询实际数据

写一个工具方法,通过下载ID查询任务的详细信息,这里就会用到那些COLUMN_*常量:

fun getDownloadDetails(downloadId: Long): String {
    val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    // 创建查询对象,过滤出当前ID的下载任务
    val query = DownloadManager.Query().setFilterById(downloadId)
    val cursor = manager.query(query)

    return if (cursor.moveToFirst()) {
        // 用COLUMN_*常量获取列的索引,再拿到对应数值
        val totalSize = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
        val downloadedSize = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
        val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))

        // 把状态转成可读文本
        val statusText = when(status) {
            DownloadManager.STATUS_PENDING -> "等待下载"
            DownloadManager.STATUS_RUNNING -> "下载中:$downloadedSize/$totalSize Bytes"
            DownloadManager.STATUS_SUCCESSFUL -> "下载完成!总大小:$totalSize Bytes"
            DownloadManager.STATUS_FAILED -> "下载失败"
            else -> "未知状态"
        }
        statusText
    } else {
        "未找到该下载任务"
    }.also {
        // 务必关闭Cursor,避免内存泄漏
        cursor.close()
    }
}

关键细节解释

  1. cursor.getColumnIndex(DownloadManager.COLUMN_XXX):这个方法会根据你传入的列名称(也就是COLUMN_*常量的值),找到该列在Cursor中的位置索引,然后你才能用getLong/getInt等方法拿到实际数据。
  2. 权限注意:别忘了在AndroidManifest.xml里添加必要权限:
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- Android 10及以下需要,11+用Scoped Storage可省略 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
    
  3. 监听下载完成:如果想在下载完成时自动获取结果,可以注册广播接收器监听DownloadManager.ACTION_DOWNLOAD_COMPLETE,然后从Intent里取出DownloadManager.EXTRA_DOWNLOAD_ID再查询数据。

内容的提问来源于stack exchange,提问作者evals

火山引擎 最新活动