Android相机拍照上传Firebase Storage无报错但未上传问题求助
问题分析与解决方案
我仔细看了你的代码,马上就发现了几个核心问题,导致拍照后既不显示进度条,也没法把图片上传到Firebase Storage:
1. 请求码不匹配,拍照结果完全没被处理
你在onActivityResult里只判断了GALLERY_INTENT,但拍照用的请求码是CAMERA_REQUEST_CODE,所以拍照完成后根本没进入处理逻辑——进度条自然不会显示,上传代码也完全没触发。
2. 默认相机Intent只返回缩略图,无法获取可上传的文件Uri
MediaStore.ACTION_IMAGE_CAPTURE默认只会返回一个小尺寸的Bitmap缩略图,data.getData()拿到的是空值,没法用来上传到Firebase Storage。你得指定一个文件路径让相机把完整照片保存到那里,再用这个文件的Uri来上传。
3. 下载Uri的获取方式错误
getDownloadUrl()是异步任务,你直接String.valueOf(downloadUri)拿到的只是Task对象,不是真实的下载链接,必须监听它的完成回调才能拿到正确的Uri。
修改后的完整代码示例
首先,在AndroidManifest.xml里添加FileProvider配置(适配Android 7.0+的文件权限):
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
然后在res/xml目录下创建file_paths.xml文件:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="my_images" path="Pictures" /> </paths>
接下来是修改后的Activity代码:
import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; import com.google.firebase.storage.UploadTask; import com.squareup.picasso.Picasso; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class New extends AppCompatActivity { private Button btn; private StorageReference mstr; private final static int CAMERA_REQUEST_CODE = 1; private ProgressBar progressBar; private ImageView img; private Uri photoUri; // 保存拍照后的文件Uri @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_new); mstr = FirebaseStorage.getInstance().getReference(); progressBar = findViewById(R.id.progressbar); img = findViewById(R.id.imageView); btn = findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dispatchTakePictureIntent(); // 调用自定义拍照方法 } }); } // 启动相机并指定照片保存路径 private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 确保有相机应用能处理这个Intent if (takePictureIntent.resolveActivity(getPackageManager()) != null) { File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { Toast.makeText(this, "创建照片文件失败", Toast.LENGTH_SHORT).show(); } // 文件创建成功后,获取Uri并启动相机 if (photoFile != null) { photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); startActivityForResult(takePictureIntent, CAMERA_REQUEST_CODE); } } } // 创建唯一的照片保存文件 private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); return File.createTempFile( imageFileName, /* 文件名前缀 */ ".jpg", /* 文件后缀 */ storageDir /* 存储目录 */ ); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); // 处理拍照返回的结果 if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK) { progressBar.setVisibility(View.VISIBLE); // 用保存的photoUri上传文件到Firebase StorageReference filepath = mstr.child("Photos").child(photoUri.getLastPathSegment()); filepath.putFile(photoUri) .addOnSuccessListener(taskSnapshot -> { Toast.makeText(New.this, "Upload done", Toast.LENGTH_LONG).show(); // 正确获取下载Uri taskSnapshot.getStorage().getDownloadUrl() .addOnSuccessListener(uri -> { // 用Picasso加载上传后的图片 Picasso.with(New.this).load(uri).fit().centerCrop().into(img); progressBar.setVisibility(View.INVISIBLE); }); }) .addOnFailureListener(e -> { // 上传失败的容错处理 Toast.makeText(New.this, "上传失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); progressBar.setVisibility(View.INVISIBLE); }); } } }
关键修改点说明
- 添加FileProvider配置:解决Android 7.0以上的文件访问权限限制,确保相机能把照片保存到指定路径。
- 自定义拍照逻辑:创建临时文件保存完整照片,获取真实的文件Uri,替代默认的缩略图返回逻辑。
- 修正请求码判断:现在会处理拍照返回的
CAMERA_REQUEST_CODE,触发进度条显示和上传流程。 - 修复下载Uri获取:通过异步回调拿到真实的下载链接,再用Picasso加载图片。
这样修改后,拍照后就能正常显示进度条,照片也会成功上传到Firebase Storage,同时在ImageView里展示上传后的图片啦。
内容的提问来源于stack exchange,提问作者Garvit




