You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

图片已上传Firebase Storage,元数据无法写入Realtime DB求助

图片上传Firebase Storage成功,但无法写入Realtime Database问题解决

问题描述

图片能正常上传到Firebase Storage,但图片名称和URL无法写入Firebase Realtime Database,这是项目推进的关键环节,急需解决。已参考同类问题方案但未成功,项目依赖配置正确,SHA-1/SHA-256已添加至Firebase控制台,对应配置文件也已更新。

原代码

package com.example.x_raydetect;

import static android.content.ContentValues.TAG;

import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AlertDialogLayout;

import com.google.android.gms.tasks.OnCanceledListener;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.OnProgressListener;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.StorageTask;
import com.google.firebase.storage.UploadTask;
import com.squareup.picasso.Picasso;

public class InsDB extends AppCompatActivity {

    private Button mainPage, btnView, btnMed, btnGallery, btnInsert, btnCamera;
    private EditText name;
    private ImageView insertImageView;
    private ProgressBar progressBar;
    public Uri imageUri;
    Bitmap bitmap;

    private StorageReference StorageRef;
    private DatabaseReference DatabaseRef;

    private StorageTask UploadTask;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ins_database);

        //menu tabs
        mainPage = findViewById(R.id.mainPage);
        btnView = findViewById(R.id.btnView);
        btnMed = findViewById(R.id.btnMed);
        //interface buttons/GUY
        btnCamera = findViewById(R.id.btnCamera);
        btnGallery = findViewById(R.id.btnGallery);
        btnInsert = findViewById(R.id.btnInsert);
        insertImageView = findViewById(R.id.insert_ImageView);
        name = findViewById(R.id.name);
        progressBar = findViewById(R.id.progressBar);

        StorageRef = FirebaseStorage.getInstance().getReference("uploads");
        DatabaseRef = FirebaseDatabase.getInstance("https://x-ray-detect-default-rtdb.asia-southeast1.firebasedatabase.app/").getReference("uploads");


        mainPage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openMainPage();
            }
        });

        btnView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openViewDB();
            }
        });

        btnMed.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        btnGallery.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openGalleryChooser();
            }
        });

        btnCamera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(intent, 12);
            }
        });

        btnInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (UploadTask != null && UploadTask.isInProgress()) {
                    Toast.makeText(InsDB.this, "Upload in progress", Toast.LENGTH_SHORT).show();
                } else {
                    insertFile();
                }

            }
        });
    }

    private void openGalleryChooser() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        startActivityForResult(intent, 10);
    }

    private String getFileExtension(Uri uri) {
        ContentResolver cR = getContentResolver();
        MimeTypeMap mime = MimeTypeMap.getSingleton();
        return mime.getExtensionFromMimeType(cR.getType(uri));
    }

    private void insertFile() {
        if (imageUri != null) {
            StorageReference fileReference = StorageRef.child(System.currentTimeMillis()
                    + "." + getFileExtension(imageUri));

            UploadTask = fileReference.putFile(imageUri)
                    .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                        @Override
                        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                            Handler handler = new Handler();
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    progressBar.setProgress(0);
                                }
                            }, 500);

                            Toast.makeText(InsDB.this, "Upload successful", Toast.LENGTH_LONG).show();
                            /*
                            Upload upload = new Upload(name.getText().toString().trim(),
                                    taskSnapshot.getMetadata().getReference().getDownloadUrl().toString());
                            String uploadId = DatabaseRef.push().getKey();
                            DatabaseRef.child(uploadId).setValue(upload);
                            */

                            Task<Uri> urlTask = taskSnapshot.getStorage().getDownloadUrl();
                            while (!urlTask.isSuccessful());
                            Uri downloadUrl = urlTask.getResult();

                            //Log.d(TAG, "onSuccess: firebase download url: " + downloadUrl.toString()); //use if testing...don't need this line.
                            Upload upload = new Upload(name.getText().toString().trim(),downloadUrl.toString());

                            String uploadId = DatabaseRef.push().getKey();
                            DatabaseRef.child(uploadId).setValue(upload)
                                    //ADDED NEW LISTENERS//
                                    .addOnSuccessListener(new OnSuccessListener<Void>() {
                                        @Override
                                        public void onSuccess(Void unused) {
                                            new AlertDialog.Builder(InsDB.this).setTitle("Success")
                                                    .setMessage(uploadId + name.getText().toString().trim() + downloadUrl.toString())
                                                    .setCancelable(true)
                                                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            finish();
                                                        }
                                                    })
                                                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            dialog.cancel();
                                                        }
                                                    })
                                                    .show();
                                        }
                                    })
                                    .addOnFailureListener(new OnFailureListener() {
                                        @Override
                                        public void onFailure(@NonNull Exception e) {
                                            new AlertDialog.Builder(InsDB.this).setTitle("Failed")
                                                    .setMessage(uploadId + name.getText().toString().trim() + downloadUrl.toString())
                                                    .setCancelable(true)
                                                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            finish();
                                                        }
                                                    })
                                                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            dialog.cancel();
                                                        }
                                                    })
                                                    .show();
                                        }
                                    })
                                    .addOnCanceledListener(new OnCanceledListener() {
                                        @Override
                                        public void onCanceled() {
                                            new AlertDialog.Builder(InsDB.this)
                                                    .setTitle("Cancelled")
                                                    .setMessage(uploadId + name.getText().toString().trim() + downloadUrl.toString())
                                                    .setCancelable(true)
                                                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            finish();
                                                        }
                                                    })
                                                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            dialog.cancel();
                                                        }
                                                    })
                                                    .show();
                                        }
                                    })
                                    .addOnCompleteListener(new OnCompleteListener<Void>() {
                                        @Override
                                        public void onComplete(@NonNull Task<Void> task) {
                                            new AlertDialog.Builder(InsDB.this)
                                                    .setTitle("Complete")
                                                    .setMessage(uploadId + name.getText().toString().trim() + downloadUrl.toString())
                                                    .setCancelable(true)
                                                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            finish();
                                                        }
                                                    })
                                                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                            dialog.cancel();
                                                        }
                                                    })
                                                    .show();
                                        }
                                    });
                        }
                    })
                    .addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Toast.makeText(InsDB.this, e.getMessage(), Toast.LENGTH_SHORT).show();
                        }
                    })
                    .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                        @Override
                        public void onProgress(UploadTask.TaskSnapshot snapshot) {
                            double progress = (100.0 * snapshot.getBytesTransferred() / snapshot.getTotalByteCount());
                            progressBar.setProgress((int) progress);
                        }
                    });
        } else {
            Toast.makeText(this, "No file selected", Toast.LENGTH_SHORT).show();
        }

    }

    public void openMainPage() {
        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
    }

    public void openViewDB() {
        Intent intent = new Intent(this, ViewDB.class);
        startActivity(intent);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 10 && data != null) {
            imageUri = data.getData();
            Picasso.with(this).load(imageUri).into(insertImageView);
        } else if (requestCode == 12) {
            if (data != null) {
                bitmap = (Bitmap) data.getExtras().get("data");
                insertImageView.setImageBitmap(bitmap);
            }

        }
    }
}

问题排查与修复方案

1. 同步获取DownloadUrl的错误方式

原代码用while (!urlTask.isSuccessful());循环等待任务完成,会阻塞线程,且可能导致任务未完成就获取结果。需改为异步监听方式处理getDownloadUrl()。

2. Camera拍照后未设置imageUri

拍照返回Bitmap后,imageUri为空,insertFile()方法不会执行上传和数据库写入逻辑。需将Bitmap转换为Uri。

3. 数据库写入监听逻辑冗余

原代码同时添加了Success、Failure、Canceled、Complete监听,会弹出多个弹窗,需调整为只在最终状态提示。

修复后的核心代码修改

处理Camera拍照后的Uri转换

修改onActivityResult中拍照部分代码,并添加Bitmap转Uri方法:

else if (requestCode == 12) {
    if (data != null) {
        bitmap = (Bitmap) data.getExtras().get("data");
        insertImageView.setImageBitmap(bitmap);
        // 将Bitmap转换为Uri
        imageUri = getImageUriFromBitmap(bitmap);
    }
}

// 添加Bitmap转Uri的方法
private Uri getImageUriFromBitmap(Bitmap bitmap) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "X-Ray Image", null);
    return Uri.parse(path);
}

修正DownloadUrl获取与数据库写入逻辑

修改insertFile()中的成功监听部分:

.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        Handler handler = new Handler();
        handler.postDelayed(() -> progressBar.setProgress(0), 500);

        Toast.makeText(InsDB.this, "上传成功", Toast.LENGTH_LONG).show();

        // 异步获取DownloadUrl
        taskSnapshot.getStorage().getDownloadUrl().addOnSuccessListener(downloadUrl -> {
            String fileName = name.getText().toString().trim();
            Upload upload = new Upload(fileName, downloadUrl.toString());
            String uploadId = DatabaseRef.push().getKey();
            
            // 写入数据库并处理结果
            DatabaseRef.child(uploadId).setValue(upload)
                    .addOnCompleteListener(task -> {
                        if (task.isSuccessful()) {
                            new AlertDialog.Builder(InsDB.this)
                                    .setTitle("操作成功")
                                    .setMessage("数据已写入数据库\nID: " + uploadId + "\n名称: " + fileName + "\nURL: " + downloadUrl)
                                    .setPositiveButton("确定", (dialog, which) -> dialog.dismiss())
                                    .show();
                        } else {
                            new AlertDialog.Builder(InsDB.this)
                                    .setTitle("操作失败")
                                    .setMessage("数据库写入失败: " + task.getException().getMessage())
                                    .setPositiveButton("确定", (dialog, which) -> dialog.dismiss())
                                    .show();
                        }
                    });
        }).addOnFailureListener(e -> {
            Toast.makeText(InsDB.this, "获取下载链接失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        });
    }
})

检查Upload类的序列化规则

确保Upload类符合Firebase Realtime Database要求:

public class Upload {
    public String name;
    public String url;

    // 必须包含无参构造函数
    public Upload() {}

    public Upload(String name, String url) {
        this.name = name;
        this.url = url;
    }

    // 可选:添加Getter方法,提升兼容性
    public String getName() { return name; }
    public String getUrl() { return url; }
}

其他注意事项

  • 检查Firebase Realtime Database规则,开发阶段可暂时设置为开放权限(上线前需修改为安全规则):
    {
      "rules": {
        ".read": true,
        ".write": true
      }
    }
    
  • 查看Logcat中FirebaseDatabase标签的错误日志,排查权限或序列化问题。

内容的提问来源于stack exchange,提问作者SamanHuin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 06:25:22