Skip to content

Fix NullPointerException in BackgroundDownload.recreate() when COLUMN_LOCAL_URI is null #40

Description

@VincentHQL

问题重现

BackgroundDownload.recreate() 方法在如下代码行存在崩溃风险:

Uri dest = Uri.parse(cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)));

如果下载未完成或本地路径尚未生成,COLUMN_LOCAL_URI 可能为 null,从而导致 Uri.parse(null) 抛出 NullPointerException。

现象

  • 下载任务过程中(未完成前)调用 recreate() 恢复任务会因上述代码崩溃。
  • cursor 其他字段如 COLUMN_URI 也可能不合法。
  • cursor 没有保证始终关闭(close)。

合理修复建议

  • 增加 null 检查:若 COLUMN_LOCAL_URI 为空,则用 Uri.EMPTY(或 null)占位,允许后续行为正常继续。
  • 优化 cursor 管理,使用 try-finally 保证 close。
  • 兼容 COLUMN_URI 为 null 时直接返回 null,防止恢复损坏任务。
  • 示例修改:
public static BackgroundDownload recreate(Context context, long id) {
    DownloadManager manager = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(id);
    Cursor cursor = manager.query(query);
    try {
        if (cursor.getCount() == 0)
            return null;
        cursor.moveToFirst();
        String urlStr = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI));
        if (urlStr == null) {
            return null;
        }
        Uri url = Uri.parse(urlStr);
        String destStr = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
        Uri dest = (destStr != null) ? Uri.parse(destStr) : Uri.EMPTY;
        return new BackgroundDownload(manager, id, url, dest);
    } finally {
        cursor.close();
    }
}
  • 建议对 checkFinished、getProgress 等 cursor 操作同样统一用 try-finally。

修复好处

  1. 避免 NPE,提升稳定性。
  2. cursor 安全释放,防内存泄漏。
  3. 更易理解和扩展,兼容不同状态的下载任务。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions