You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动