创建用户时调用setPhotoUri报错:对象不存在于指定位置
问题根源:异步操作顺序错误
你遇到的com.google.firebase.storage.StorageException: Object does not exist at location错误,核心原因是Firebase的Storage操作是异步执行的,你的代码没有等待图片上传完成就去获取下载URL,而且更新用户资料的逻辑也跑在了URL获取完成之前。
具体来说:
- 调用
uploadImage()后立刻执行getImageUrl(),但ref.putFile(filePath)还在后台上传,这时候Storage里还没有这个文件,自然会提示"对象不存在"。 - 就算上传侥幸完成了,
downloadUri的赋值也是在getImageUrl()的异步回调里,你在回调外部直接调用user.updateProfile(profileUpdates)时,downloadUri大概率还是null,根本没拿到正确的URL。
解决方案:按异步流程链式调用
我们需要把操作按顺序串起来:用户创建成功 → 上传图片(等待完成)→ 获取下载URL(等待完成)→ 更新用户资料 → 后续逻辑。
下面是修改后的完整代码:
1. 调整创建用户的逻辑
auth.createUserWithEmailAndPassword(email, password) .addOnCompleteListener(SignupActivity.this, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { Toast.makeText(SignupActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show(); progressBar.setVisibility(View.GONE); if (!task.isSuccessful()) { Toast.makeText(SignupActivity.this, "Authentication failed." + task.getException(), Toast.LENGTH_SHORT).show(); } else { user = auth.getCurrentUser(); if(user != null){ // 调用带回调的上传方法,确保上传完成后再执行后续操作 uploadImageAndProceed(); } } } });
2. 重构上传和获取URL的方法
private void uploadImageAndProceed() { if(filePath != null && user != null) { ref = storageReference.child("UserProfileImages/" + user.getEmail()); // 等待上传完成后再执行下一步 ref.putFile(filePath) .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // 上传成功后,获取下载URL getImageUrlAndUpdateProfile(); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(SignupActivity.this, "图片上传失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } else { Toast.makeText(SignupActivity.this, "请选择要上传的图片", Toast.LENGTH_SHORT).show(); } } private void getImageUrlAndUpdateProfile() { ref.getDownloadUrl() .addOnSuccessListener(new OnSuccessListener<Uri>() { @Override public void onSuccess(Uri uri) { downloadUri = uri; Log.i("Class","Photo URL: " + downloadUri); // 拿到URL后,再更新用户资料 UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder() .setPhotoUri(downloadUri) .setDisplayName(displayNameString) .build(); user.updateProfile(profileUpdates) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void unused) { // 资料更新成功后,再执行退出登录和跳转逻辑 FirebaseAuth.getInstance().signOut(); Intent intent = new Intent(SignupActivity.this, LoginActivity.class); intent.putExtra("Email", user.getEmail()); if (downloadUri != null){ intent.putExtra("Image", downloadUri.toString()); } startActivity(intent); Toast.makeText(SignupActivity.this, "Verifique su contraseña", Toast.LENGTH_SHORT).show(); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(SignupActivity.this, "更新用户资料失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { Log.i("Class","获取图片URL出错:" + exception.toString()); Toast.makeText(SignupActivity.this, "获取图片URL失败:" + exception.getMessage(), Toast.LENGTH_SHORT).show(); } }); }
关键修改点说明
- 将上传和URL获取的逻辑链式绑定,确保每一步都等待前一步异步操作完成。
- 把用户资料更新的代码移到
getDownloadUrl()的成功回调里,保证downloadUri已经被正确赋值。 - 给每个异步操作都添加了
OnFailureListener,方便排查错误。 - 跳转逻辑放在
updateProfile()的成功回调里,确保用户资料已经更新完成。
内容的提问来源于stack exchange,提问作者Fran Tardencilla
相关产品推荐
相关产品推荐

