如何在实时 Firebase 数据库中保存上传图片的完美 url-link?
Posted
技术标签:
【中文标题】如何在实时 Firebase 数据库中保存上传图片的完美 url-link?【英文标题】:How to save the perfect url-link of uploaded image in Realtime Firebase database? 【发布时间】:2021-07-20 18:31:32 【问题描述】:我正在使用以下代码上传图像并将文本和 URL 链接保存到 Realtime firebase 数据库,但我无法使用保存的 URL 链接访问图像。我在做什么错误?如何在 Firebase 中保存上传图片的完美 URL 链接?
MainActivity.java 的代码
package com.example.project1;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
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 com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
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.UploadTask;
import com.squareup.picasso.Picasso;
public class MainActivity extends AppCompatActivity
private static final int PICK_IMAGE_REQUEST = 1;
Button mButtonChooseImage;
EditText mEditTextFileName;
ImageView mImageView;
ProgressBar mProgressBar;
Uri mImageUri;
Button mButtonUpload;
StorageReference mStorageRef;
DatabaseReference mDatabaseRef;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonChooseImage = findViewById(R.id.button_choose_image);
mButtonChooseImage.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
openFileChooser();
);
mEditTextFileName = findViewById(R.id.edit_text_file_name);
mImageView = findViewById(R.id.image_view);
mButtonUpload = findViewById(R.id.button_upload);
mProgressBar = findViewById(R.id.progress_bar);
mStorageRef = FirebaseStorage.getInstance().getReference("products");
mDatabaseRef = FirebaseDatabase.getInstance().getReference("products");
mButtonUpload.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
uploadFile();
);
private void openFileChooser()
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, PICK_IMAGE_REQUEST);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK
&& data != null && data.getData() != null)
mImageUri = data.getData();
Picasso.with(this).load(mImageUri).into(mImageView);
private String getFileExtension(Uri uri)
ContentResolver cR = getContentResolver();
MimeTypeMap mime = MimeTypeMap.getSingleton();
return mime.getExtensionFromMimeType(cR.getType(uri));
//
private void uploadFile()
if (mImageUri != null)
StorageReference fileReference = mStorageRef.child(System.currentTimeMillis() + "." + getFileExtension(mImageUri));
UploadTask uploadTask = fileReference.putFile(mImageUri);
uploadTask.addOnFailureListener(new OnFailureListener()
@Override
public void onFailure(@NonNull Exception exception)
// Handle unsuccessful uploads
Toast.makeText(MainActivity.this, exception.getMessage(), Toast.LENGTH_SHORT).show();
).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>()
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot)
Handler handler = new Handler();
handler.postDelayed(new Runnable()
@Override
public void run()
mProgressBar.setProgress(0);
, 500);
Toast.makeText(MainActivity.this, "Upload successful", Toast.LENGTH_LONG).show();
).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>()
@Override
public void onProgress(@NonNull UploadTask.TaskSnapshot snapshot)
double progress = (100.0 * snapshot.getBytesTransferred()/snapshot.getTotalByteCount());
mProgressBar.setProgress((int) progress);
);
// get download URL
Task<Uri> urlTask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>()
@Override
public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception
if (!task.isSuccessful())
throw task.getException();
// Continue with the task to get the download URL
Task<Uri> url1 = fileReference.getDownloadUrl();
Upload upload = new Upload(mEditTextFileName.getText().toString().trim(), url1.toString());
String uploadId = mDatabaseRef.push().getKey();
mDatabaseRef.child(uploadId).setValue(upload);
// Toast.makeText(MainActivity.this, "Url : "+url1, Toast.LENGTH_LONG).show();
return fileReference.getDownloadUrl();
).addOnCompleteListener(new OnCompleteListener<Uri>()
@Override
public void onComplete(@NonNull Task<Uri> task)
if (task.isSuccessful())
Uri downloadUri = task.getResult();
else
// Handle failures
// ...
);
Upload.java 的代码:
package com.example.project1;
public class Upload
private String mName;
private String mImageUrl;
public Upload()
//empty constructor needed
public Upload(String name, String imageUrl)
if (name.trim().equals(""))
name = "No Name";
mName = name;
mImageUrl = imageUrl;
public String getName()
return mName;
public void setName(String name)
mName = name;
public String getImageUrl()
return mImageUrl;
public void setImageUrl(String imageUrl)
mImageUrl = imageUrl;
activity_main.xml的XML代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/text_view_show_uploads"
android:layout_
android:layout_
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginStart="30dp"
android:layout_marginLeft="30dp"
android:layout_marginEnd="30dp"
android:layout_marginRight="30dp"
android:gravity="center"
android:text="Upload Product Images"
android:textColor="#f00fff"
android:textSize="25sp" />
<Button
android:id="@+id/button_choose_image"
android:layout_
android:layout_
android:layout_below="@id/text_view_show_uploads"
android:layout_marginTop="50dp"
android:text="Choose file" />
<EditText
android:id="@+id/edit_text_file_name"
android:layout_
android:layout_
android:layout_marginStart="16dp"
android:layout_toEndOf="@+id/button_choose_image"
android:layout_below="@id/text_view_show_uploads"
android:layout_marginTop="50dp"
android:hint="Enter file name"
android:layout_marginLeft="16dp"
android:layout_toRightOf="@+id/button_choose_image" />
<ImageView
android:id="@+id/image_view"
android:layout_
android:layout_
android:layout_above="@id/progress_bar"
android:layout_below="@id/edit_text_file_name"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginTop="20dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp" />
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_
android:layout_
android:layout_above="@+id/button_upload"
android:layout_marginBottom="16dp" />
<Button
android:id="@+id/button_upload"
android:layout_
android:layout_
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Upload" />
</RelativeLayout>
没有错误,但上传的 URL 链接无法正常访问上传的图片。数据架构
上传的图片 URL 在 firebase 架构中显示为 ("com.google.android.gms.tasks.zzu@b72c6eb")。但完美的图片 URL 链接看起来像“https://firebasestorage.googleapis.com/v0/b/rewabazar-a2258.appspot.com/o/products%2F1619256818173.jpg?alt=media&token=a3f4acd3-e0fc-49d9-8548- 5e386bc2de84"
【问题讨论】:
您在Task<Uri>
上调用 .toString()
,它只会打印出类名。您可能需要访问任务中的 URL。
【参考方案1】:
您的代码中有两个主要问题。第一个,您正在定义以下 StorageReference 对象,如下所示:
StorageReference fileReference = mStorageRef.child(System.currentTimeMillis() + "." + getFileExtension(mImageUri));
然后,您正在使用:
Task<Uri> url1 = fileReference.getDownloadUrl();
StorageReference 的“getDownloadUrl()”方法返回一个 Task 对象。只需在这样的对象上调用“toString()”,然后将其传递给 Upload 类构造函数:
Upload upload = new Upload(mEditTextFileName.getText().toString().trim(), url1.toString());
没有任何意义,因为该对象的字符串表示不是实际的 URL,它和内存中的地址,因此:
com.google.android.gms.tasks.zzu@b72c6eb
而不是:
https://firebasestorage.googleapis.com/v0/b/rewabazar-a2258.appspot.com/o/products%2F1619256818173.jpg?alt=media&token=a3f4acd3-e0fc-49d9-8548-5e386bc2de84
这是获取下载 URL 的推荐方式:
How to get the download url from Firebase Storage?第二个问题是您在数据库中的字段名称与您班级中的字段名称不同。见“mImageUrl”与“imageUrl”?这是不正确的,两个名称必须匹配。您要么更改数据库中字段的名称以匹配类中的字段名称,要么在 getter 前面使用注释:
@PropertyName("imageUrl")
public String getImageUrl()
return mImageUrl;
这是单个属性的示例,但您也应该为其他属性做同样的事情。
【讨论】:
以上是关于如何在实时 Firebase 数据库中保存上传图片的完美 url-link?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Firebase 上传图片的图片下载 URL 转换为 base64
如何将从firebase存储上传的图像保存到firestore数据库中的currentUser
如何使用具有离子和角度的照片相机在firebase中同时保存多个图像
如何限制用户在 Firebase 实时数据库中上传一定数量的数据