Android端Firebase Storage重复上传文件时进度条及状态图标不更新问题
解决Firebase Storage二次上传进度条不更新的问题
看起来你遇到的问题是典型的集合索引错位加上缺少上传完成回调导致的,我之前做类似功能时也踩过这个坑!咱们一步步拆解问题,然后修复它:
问题根源分析
- 索引不匹配:你在循环里用
final int index = i;,但这个i是当前选中批次文件的局部索引(比如第二次选2个文件,i从0开始),而uploadFiles是往集合末尾追加元素,新文件的真实索引应该是uploadFiles.size()-1,不是i。这就导致第二次上传时,你更新的是progressValue的前几个位置(对应第一次上传的文件),而新文件的位置根本没被更新,所以进度条没反应。 - 缺少上传完成回调:你的代码只处理了上传进度,没有监听上传成功/失败的事件,所以上传完成后没法把状态改成"Done",自然也不会显示勾选图标。
- progressValue操作混乱:你在
onProgress里先remove再add元素,很容易导致集合大小和另外两个(uploadFiles、uploadStatus)不一致,进一步加剧索引错位。
修复方案
1. 修正索引逻辑,保证三个集合索引一一对应
每次添加新文件到uploadFiles后,获取它在全局集合中的真实位置,而不是用循环的局部i:
2. 初始化progressValue元素,保持集合同步
添加文件时,同时给progressValue加入初始进度0,确保三个集合的size始终相同,索引完全对应。
3. 完善上传的全生命周期回调
添加成功、失败的监听,更新状态并刷新UI。
4. 简化progressValue的更新方式
直接通过索引设置进度值,不需要remove再add,避免集合结构混乱。
修改后的核心代码
UploadActivity中文件选择与上传逻辑
// 先确保progressValue初始化(比如在onCreate里) progressValue = new ArrayList<>(); ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) { return; // 先判断结果是否有效,避免空指针 } Intent intentReceived = result.getData(); ClipData clipData = intentReceived.getClipData(); if (clipData != null) { for (int i = 0; i < clipData.getItemCount(); i++) { Uri fileUri = clipData.getItemAt(i).getUri(); String fileName = UploadActivity.this.getFileNameFromUri(fileUri); // 添加到集合,获取真实索引 uploadFiles.add(fileName); uploadStatus.add("Loading"); progressValue.add(0); // 初始化进度为0 int itemPosition = uploadFiles.size() - 1; // 这才是新文件的真实索引 adapter.notifyItemInserted(itemPosition); // 用notifyItemInserted更高效 // 上传逻辑 StorageReference uploader = storageReference.child("/" + Path).child(fileName); uploader.putFile(fileUri) .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(@NonNull UploadTask.TaskSnapshot snapshot) { double progress = (100.0 * snapshot.getBytesTransferred()) / snapshot.getTotalByteCount(); int currentProgress = (int) progress; // 直接设置对应位置的进度值,不需要remove/add progressValue.set(itemPosition, currentProgress); uploadStatus.set(itemPosition, "Processing"); adapter.notifyItemChanged(itemPosition); // 只更新当前项,更高效 } }) .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { uploadStatus.set(itemPosition, "Done"); adapter.notifyItemChanged(itemPosition); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { uploadStatus.set(itemPosition, "Failed"); adapter.notifyItemChanged(itemPosition); // 可以在这里添加失败提示 } }); } } else { // 处理单个文件选择的情况(你之前的代码没处理这个分支,建议补上) Uri fileUri = intentReceived.getData(); if (fileUri != null) { String fileName = UploadActivity.this.getFileNameFromUri(fileUri); uploadFiles.add(fileName); uploadStatus.add("Loading"); progressValue.add(0); int itemPosition = uploadFiles.size() - 1; adapter.notifyItemInserted(itemPosition); StorageReference uploader = storageReference.child("/" + Path).child(fileName); uploader.putFile(fileUri) .addOnProgressListener(snapshot -> { double progress = (100.0 * snapshot.getBytesTransferred()) / snapshot.getTotalByteCount(); int currentProgress = (int) progress; progressValue.set(itemPosition, currentProgress); uploadStatus.set(itemPosition, "Processing"); adapter.notifyItemChanged(itemPosition); }) .addOnSuccessListener(taskSnapshot -> { uploadStatus.set(itemPosition, "Done"); adapter.notifyItemChanged(itemPosition); }) .addOnFailureListener(e -> { uploadStatus.set(itemPosition, "Failed"); adapter.notifyItemChanged(itemPosition); }); } } });
补充Adapter的小优化
可以给状态判断加个else分支,处理"Loading"或"Failed"的情况,避免UI异常:
@Override public void onBindViewHolder(@NonNull uploadViewHolder holder, int position) { String fileName = files.get(position); if(fileName.length() > 25) fileName = fileName.substring(0,25)+"..."; holder.uploadFileName.setText(fileName); String fileStatus = status.get(position); switch (fileStatus) { case "Processing": holder.uploadProgressBar.setVisibility(View.VISIBLE); int updateProgress = progress.get(position); holder.uploadProgressBar.setProgress(updateProgress); holder.uploadComplete.setVisibility(View.GONE); break; case "Done": holder.uploadProgressBar.setVisibility(View.GONE); holder.uploadComplete.setImageResource(R.drawable.check_circle); holder.uploadComplete.setVisibility(View.VISIBLE); break; case "Loading": holder.uploadProgressBar.setVisibility(View.VISIBLE); holder.uploadProgressBar.setProgress(0); holder.uploadComplete.setVisibility(View.GONE); break; case "Failed": holder.uploadProgressBar.setVisibility(View.GONE); holder.uploadComplete.setImageResource(R.drawable.error_circle); // 可以加个错误图标 holder.uploadComplete.setVisibility(View.VISIBLE); break; default: holder.uploadProgressBar.setVisibility(View.GONE); holder.uploadComplete.setVisibility(View.GONE); break; } }
额外建议
- 用
notifyItemInserted和notifyItemChanged代替notifyDataSetChanged,前者只更新变化的项,性能更好,也能避免不必要的UI刷新。 - 记得在Activity销毁时取消未完成的上传任务,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Krutarth Vaishnav
相关产品推荐
相关产品推荐

