如何在我的应用程序上显示来自 Firebase 存储的图像?

Posted

技术标签:

【中文标题】如何在我的应用程序上显示来自 Firebase 存储的图像?【英文标题】:How to show an image on my app from firebase storage? 【发布时间】:2021-08-23 16:37:43 【问题描述】:

我不能让应用程序在我的 android 应用程序上显示个人资料图片,我可以成功上传它,但在应用程序中显示它的代码不起作用。 问题是我的应用程序无法转换图像中的 firebase 链接,我真的不知道为什么,代码与 youtube 教程中的完全相同。

ProfileActivity.java

package com.example.scrapbase11;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.squareup.picasso.Picasso;
import com.theartofdev.edmodo.cropper.CropImage;
import com.theartofdev.edmodo.cropper.CropImageView;

import de.hdodenhof.circleimageview.CircleImageView;

public class ProfileActivity extends AppCompatActivity 

    private CircleImageView Profileimage;
    private TextView usernickname, userfirstlastname, usercomment, registrationdate;
    private FirebaseAuth mAuth;
    private DatabaseReference UsersRef;
    private StorageReference UserProfileImageRef;
    private ProgressDialog loadingBar;
    private String currentuserid;
    final static int Gallery_Pick = 1;

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

        loadingBar = new ProgressDialog(this);
        mAuth = FirebaseAuth.getInstance();
        currentuserid = mAuth.getCurrentUser().getUid();
        UserProfileImageRef = FirebaseStorage.getInstance().getReference().child("Profile Images");
        usernickname = (TextView) findViewById(R.id.profile_nickname);
        UsersRef = FirebaseDatabase.getInstance().getReference().child("Users").child(currentuserid);
        userfirstlastname = (TextView) findViewById(R.id.profile_firstlastname);
        usercomment = (TextView) findViewById(R.id.profile_comment);
        Profileimage = (CircleImageView) findViewById(R.id.my_profile_pic);
        registrationdate= (TextView) findViewById(R.id.terzarow);

        UsersRef.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) 
             if (snapshot.exists())

                 String myusernickname = snapshot.child("nickname").getValue().toString();
                 String myusercomment = snapshot.child("status").getValue().toString();
                 String myfamilyname = snapshot.child("familyname").getValue().toString();
                 String mygivenname = snapshot.child("givenname").getValue().toString();
                 String myregistrationdate = snapshot.child("registrationdate").getValue().toString();

                 usernickname.setText("@" + myusernickname);
                 usercomment.setText(myusercomment);
                 userfirstlastname.setText(mygivenname + " " + myfamilyname);
                 registrationdate.setText(myregistrationdate);
             
             else 
                 Toast.makeText(ProfileActivity.this, "Errore del database", Toast.LENGTH_SHORT).show();
             
            

            @Override
            public void onCancelled(@NonNull DatabaseError error) 

            
        );

        Profileimage.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                Intent galleryIntent = new Intent();
                galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
                galleryIntent.setType("image/*");
                startActivityForResult(galleryIntent, Gallery_Pick);
            
        );



        UsersRef.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot snapshot)
            
                if(snapshot.exists())
                
                    if (snapshot.hasChild("profileimage"))
                    
                        String image = snapshot.child("profileimage").getValue().toString();
                        Picasso.get().load(image).into(Profileimage);
                    
                    else
                    
                        Toast.makeText(ProfileActivity.this, "Please select profile image first.", Toast.LENGTH_SHORT).show();
                    
                
            

            @Override
            public void onCancelled(DatabaseError databaseError) 

            
        );
    

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode==Gallery_Pick && resultCode==RESULT_OK && data!=null)
        
            Uri ImageUri = data.getData();
            CropImage.activity()
                    .setGuidelines(CropImageView.Guidelines.ON)
                    .setAspectRatio(1, 1)
                    .start(this);

        
        if(requestCode==CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE)
            CropImage.ActivityResult result = CropImage.getActivityResult(data);

            if(resultCode == RESULT_OK)
                loadingBar.setTitle("Profile image updating");
                loadingBar.setMessage("Please wait...");
                loadingBar.show();
                loadingBar.setCanceledOnTouchOutside(true);

                Uri resultUri = result.getUri();

                StorageReference filePath = UserProfileImageRef.child(currentuserid + ".jpg");
                filePath.putFile(resultUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() 
                    @Override
                    public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) 
                        
                            if (task.isSuccessful())

                                final String downloadUrl = task.getResult().getStorage().getDownloadUrl().toString();
                                UsersRef.child("profileimage").setValue(currentuserid + ".jpg")
                                        .addOnCompleteListener(new OnCompleteListener<Void>() 
                                            @Override
                                            public void onComplete(@NonNull Task<Void> task) 
                                                if(task.isSuccessful())
                                                    Intent setupIntent = new Intent(ProfileActivity.this, ProfileActivity.class);
                                                    startActivity(setupIntent);
                                                    Toast.makeText(ProfileActivity.this, "Profile Image stored succesfully", Toast.LENGTH_SHORT).show();
                                                    loadingBar.dismiss();
                                                
                                                else 
                                                    String message = task.getException().getMessage();
                                                    loadingBar.dismiss();
                                                    Toast.makeText(ProfileActivity.this, "Error Occured", Toast.LENGTH_SHORT).show();
                                                
                                            
                                        );
                            
                        
                    
                );

            
            else 
                Toast.makeText(this, "Error occured: Image can't be cropped. Try again", Toast.LENGTH_SHORT).show();
                loadingBar.dismiss();
            

        
    

这是代码的主要部分,其中包括显示图像的部分:

 if(snapshot.exists())
                
                    if (snapshot.hasChild("profileimage"))
                    
                        String image = snapshot.child("profileimage").getValue().toString();
                        Picasso.get().load(image).into(Profileimage);
                    

编辑:我也试过把 UsersRef.child("profileimage").setValue(downloadUrl) 但是结果是一样的,只是数据库中profileimage的代码不同,这是result

【问题讨论】:

你有没有试过检查如果任务不成功会发生什么? 【参考方案1】:

这样做的方法不是像你那样获取字符串,而是你需要一个异步任务并处理成功方法,例如在我的函数中

    /**
 * Function that send the new photo to our Firebase Storage
 */
private void updatePhoto() 

    runOnUiThread(() -> 
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        final byte[] data = baos.toByteArray();
        final UploadTask uploadTask = mStorage.child("Users_Profiles").child(userName).putBytes(data);
        uploadTask.addOnFailureListener(e -> 
            progressDialog.dismiss();
            Toast.makeText(ProfileActivity.this, "Photo upload failed, please try again.", Toast.LENGTH_SHORT).show();
        ).addOnSuccessListener(taskSnapshot -> 
            if (taskSnapshot.getMetadata() != null) 
                if (taskSnapshot.getMetadata().getReference() != null) 
                    Task<Uri> result = taskSnapshot.getStorage().getDownloadUrl();
                    result.addOnSuccessListener(uri -> 
                        imageURL = uri.toString();
                        ref.child("Users").child(userName).child("pic_url").setValue(imageURL);
                        progressDialog.dismiss();
                    );
                
            
        );
    );


如您所见,我首先将照片转换为 byte[] 数据,然后使用 uploadTask 上传文件。 这样做之后,我使用 OnSuccessListner 来确保我的文件实际上传到了 firestore,然后我使用 Task 结果来获取文件 URL

taskSnapshot.getStorage().getDownloadUrl();

然后,当您拥有该链接时,您可以在代码中随意使用它

  Picasso.get().load(image).into(imageURL);

imageURL 只是为了让您理解这是我用来使用 Picasso 将图像加载到 ImageView 的字符串。

如果对你有帮助,你可以使用我的功能或修改它。

【讨论】:

谢谢 Yakir,我只是不明白 imageBitmap 应该是什么。它是我在 CircleImageView 中的 Profileimage 的等价物吗? imageBitmap 只是我存储在 imageView 中然后压缩它的图像(我写了一个函数来减小文件大小,如果你也想要的话,请告诉我)。之后,我在数据字节对象中使用它来将其存储在 Firestore 中,然后在该过程完成后下载它。如果这个答案对你有帮助,请给它投票:)【参考方案2】:

替换

UsersRef.child("profileimage").setValue(currentuserid + ".jpg")

UsersRef.child("profileimage").setValue(downloadUrl)

编辑-:

也可以先调用addOnSuccessListener而不是addOnCompleteListener

.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() 
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) 
        String image = taskSnapshot.getDownloadUrl().toString());
    
);

onSuccess内部调用addOnCompleteListener

【讨论】:

嗨,Krishan,如果我没有告诉你,我很抱歉。我已经尝试过这种方法,不幸的是结果是一样的。我现在更新我的帖子 看看我放的最后一张照片,它给了我“com.google.android.gms.tasks.zzu@382793f” 检查编辑后的答案。你没有从final String downloadUrl = task.getResult().getStorage().getDownloadUrl().toString();得到网址【参考方案3】:

我有一个简单的方法给你,它对我有用:

在您的应用中设置 firebase 和 firebase-storage 后...

第一:

xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="@color/white">

<ImageView
    android:id="@+id/imageView"
    android:layout_
    android:layout_ />

</androidx.constraintlayout.widget.ConstraintLayout>

秒:

MainActivity:

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;

public class MainActivity extends AppCompatActivity 

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

    ImageView imageView = (ImageView) findViewById(R.id.imageView);

    FirebaseStorage firebaseStorage = FirebaseStorage.getInstance();

    StorageReference storageReference = firebaseStorage.getReference();

    storageReference.child("images/main.jpg").getBytes(Long.MAX_VALUE).addOnSuccessListener(new OnSuccessListener<byte[]>() 
        @Override
        public void onSuccess(byte[] bytes) 
            Bitmap bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
            imageView.setImageBitmap(bitmap);
        
    ).addOnFailureListener(new OnFailureListener() 
        @Override
        public void onFailure(@NonNull Exception exception) 
            // Handle any errors
        
    );




【讨论】:

以上是关于如何在我的应用程序上显示来自 Firebase 存储的图像?的主要内容,如果未能解决你的问题,请参考以下文章

如何在反应js中显示来自firebase存储的所有图像

在 Flutter 中,如何使用 CachedNetworkImage 显示来自 Firebase 的离线图像?

如何在 Android 中使用适配器显示来自 Firebase 的组列表?

如何在我的 firebase 和 flutter 应用上创建实时用户数?

从 Firebase 更新值后,如何停止 reloadData 滚动到我的应用顶部?

如何将来自不同组件的 firebase auth 和 Cloud Firestore 用作单个 Firebase 应用程序