如何在实时 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&lt;Uri&gt; 上调用 .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 实时数据库中上传一定数量的数据

将多张图片上传到 Firebase 并检索到 viewpage

将相机图像上传到 Firebase