Skip to content

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

@VincentHQL

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions