Android 如何在所有图片上传至Firebase完成后再关闭Activity
问题根源
你遇到的问题核心是 Firebase Storage的上传操作是异步执行的,for循环会同步遍历完所有图片立刻执行结束,不会等待异步上传回调返回,所以直接在循环后调用finish()会提前关闭页面。同时当前代码存在变量作用域bug:循环中使用的成员变量imagePath会被多次覆盖,最终StoreLink方法取到的都是最后一次循环的路径,会导致数据库存储路径错误。
解决方案
- 用原子计数器统计上传完成的数量,异步回调多线程场景下用
AtomicInteger可避免计数错乱 - 把
imagePath改为循环内局部变量,通过参数传递给StoreLink方法,避免被循环覆盖 - 每次上传+数据库存链接的流程全部完成后更新计数器,计数等于总图片数时再调用
finish() - 添加上传/存库失败的分支处理,避免出错时页面永远无法关闭
修改后的上传循环代码
// 先获取总上传数量 int totalUploadCount = ImageList.size(); // 原子计数器,记录完成上传+存数据库的任务数量 AtomicInteger completedCount = new AtomicInteger(0); for (int uploadCount = 0; uploadCount < totalUploadCount; uploadCount++) { // imagePath改成局部变量,不要用成员变量,避免被后续循环覆盖 String imagePath = productRef.child(UID).child("images").push().getKey(); Uri IndividualImage = ImageList.get(uploadCount); StorageReference ImageName = productImagesRef.child(UID).child(imagePath); // 压缩图片 Bitmap bmp = null; try { bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), IndividualImage); } catch (IOException e) { e.printStackTrace(); // 读取图片失败也要更新计数,避免页面卡住 int current = completedCount.incrementAndGet(); if (current == totalUploadCount) { Toast.makeText(this, "部分图片读取失败", Toast.LENGTH_SHORT).show(); finish(); } continue; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.JPEG, 25, baos); byte[] data = baos.toByteArray(); // 上传压缩后的图片 ImageName.putBytes(data) .addOnSuccessListener(taskSnapshot -> ImageName.getDownloadUrl() .addOnSuccessListener(uri -> { String url = String.valueOf(uri); // 把imagePath、计数器、总数量作为参数传给StoreLink StoreLink(url, imagePath, completedCount, totalUploadCount); })) .addOnFailureListener(e -> { // 上传失败更新计数 int current = completedCount.incrementAndGet(); if (current == totalUploadCount) { Toast.makeText(this, "部分图片上传失败", Toast.LENGTH_SHORT).show(); finish(); } }); }
修改后的StoreLink方法
private void StoreLink(String url, String imagePath, AtomicInteger completedCount, int totalUploadCount) { HashMap<String ,Object> hashMap = new HashMap<>(); hashMap.put("image", url); hashMap.put("id", imagePath); productRef.child(UID).child("images").child(imagePath).updateChildren(hashMap) .addOnCompleteListener(task -> { // 不管数据库存储成功失败都更新计数 int current = completedCount.incrementAndGet(); if (current == totalUploadCount) { // 所有任务处理完成,先关闭弹窗再关闭页面 if (dialog != null && dialog.isShowing()) { dialog.dismiss(); } Toast.makeText(this, "上传任务全部处理完成", Toast.LENGTH_SHORT).show(); finish(); } }); }
可选优化
如果要求所有图片必须全部上传成功才关闭页面,可以额外增加失败计数器,最终判断失败数为0时再走成功逻辑,否则提示用户上传失败。如果需要上传大量图片,建议配合前台服务实现,避免页面被系统回收导致上传中断。
内容的提问来源于stack exchange,提问作者user17547007
相关产品推荐
相关产品推荐

