You need to enable JavaScript to run this app. 如何实现从Firebase下载PDF文件时同步更新进度条显示下载进度
优惠活动
大模型
产品
解决方案
定价
更多

如何实现从Firebase下载PDF文件时同步更新进度条显示下载进度

实现方案1:使用Firebase Storage原生下载接口(更推荐,无系统依赖)

该方案不需要调用getDownloadUrl,直接通过StorageReference写入本地文件,自带实时进度回调,官方维护无废弃风险,兼容所有支持Firebase的Android版本。

  • 前置要求:确保build.gradle已引入最新的Firebase Storage依赖;若将文件保存到公共存储目录,需适配对应Android版本的存储权限
// 全局变量保存下载任务,方便需要时取消
private FileDownloadTask mDownloadTask;

public void downloadWithProgress() {
    storageReference = FirebaseStorage.getInstance().getReference();
    StorageReference ref = storageReference.child("fileName.pdf");
    
    // 本地保存路径,示例为应用私有下载目录,无需额外权限
    File localFile = new File(getExternalFilesDir(DIRECTORY_DOWNLOADS), "fileName.pdf");
    
    mDownloadTask = ref.getFile(localFile);
    
    // 监听下载进度
    mDownloadTask.addOnProgressListener(taskSnapshot -> {
        // 计算进度百分比
        int progress = (int) ((100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount());
        // 此处直接更新你的UI进度条即可,例如 progressBar.setProgress(progress)
        Log.d("下载进度", "当前进度: " + progress + "%");
    }).addOnSuccessListener(taskSnapshot -> {
        // 下载成功,处理后续逻辑
        Toast.makeText(className.this, "文件下载完成", Toast.LENGTH_SHORT).show();
    }).addOnFailureListener(e -> {
        // 下载失败处理
        Toast.makeText(className.this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
    });
}

// 如需支持取消下载,调用该方法即可
private void cancelDownload() {
    if (mDownloadTask != null) {
        mDownloadTask.cancel();
    }
}

该方案进度回调实时准确,不需要额外轮询,原生支持断点续传和取消下载


实现方案2:保留现有DownloadManager实现,增加进度监听

如果不想改动现有下载逻辑,可以通过定时轮询DownloadManager的任务状态获取进度,实现如下:

// 保存DownloadManager的任务ID
private long mDownloadId;
// 定时查询进度的Handler
private Handler mProgressHandler = new Handler(Looper.getMainLooper());
// 查询进度的Runnable
private Runnable mProgressRunnable;

public void download(){
    storageReference = FirebaseStorage.getInstance().getReference();
    StorageReference ref = storageReference.child("fileName.pdf");
    ref.getDownloadUrl().addOnSuccessListener(uri -> {
        String url = uri.toString();
        // 接收返回的下载任务ID
        mDownloadId = downloadPdf(className.this,"fileName",".pdf",DIRECTORY_DOWNLOADS,url);
        // 开始监听进度
        startListenDownloadProgress();
    }).addOnFailureListener(e -> {
        // 处理获取下载链接失败逻辑
    });
}

public long downloadPdf(Context context, String fileName, String fileExtensions, String destinationDirectory, String url){
    DownloadManager downloadManager= (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    Uri uri = Uri.parse(url);
    DownloadManager.Request request = new DownloadManager.Request(uri);
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    request.setDestinationInExternalFilesDir(context, destinationDirectory, fileName+fileExtensions);
    // 返回任务ID用于后续查询进度
    return downloadManager.enqueue(request);
}

// 开始监听下载进度
private void startListenDownloadProgress() {
    DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    mProgressRunnable = new Runnable() {
        @Override
        public void run() {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(mDownloadId);
            Cursor cursor = downloadManager.query(query);
            if (cursor.moveToFirst()) {
                int status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
                switch (status) {
                    case DownloadManager.STATUS_RUNNING:
                        long downloaded = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                        long total = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                        int progress = (int) ((downloaded * 100) / total);
                        // 此处更新UI进度条
                        Log.d("下载进度", "当前进度: " + progress + "%");
                        // 每500毫秒查询一次,可自行调整间隔
                        mProgressHandler.postDelayed(this, 500);
                        break;
                    case DownloadManager.STATUS_SUCCESSFUL:
                        // 下载完成,移除回调避免内存泄漏
                        mProgressHandler.removeCallbacks(this);
                        Toast.makeText(className.this, "下载完成", Toast.LENGTH_SHORT).show();
                        break;
                    case DownloadManager.STATUS_FAILED:
                        // 下载失败,移除回调
                        mProgressHandler.removeCallbacks(this);
                        break;
                }
            }
            cursor.close();
        }
    };
    mProgressHandler.post(mProgressRunnable);
}

// 页面销毁时移除回调,避免内存泄漏
@Override
protected void onDestroy() {
    super.onDestroy();
    if (mProgressHandler != null && mProgressRunnable != null) {
        mProgressHandler.removeCallbacks(mProgressRunnable);
    }
}

该方案需要自行处理内存泄漏,进度更新频率可根据需求调整,注意部分定制ROM可能限制DownloadManager的状态查询权限


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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 19:54:04