如何实现从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
相关产品推荐
相关产品推荐

