displaying firebase storage images in a RecyclerView

16,574

Solution 1

I suggest you add setImage method on your RecyclerView.ViewHolder and store the url of your image in the object that you retrieve in your FirebaseRecyclerAdapter.

In my case, I'm using a Glide to manage the images of my app:

My ViewHolder Example:

public class UserListViewHolder extends RecyclerView.ViewHolder {
private final View mView;
private static final int POST_TEXT_MAX_LINES = 6;
private ImageView mIconView;
private TextView mAuthorView;
private UserClickListener mListener;

public UserListViewHolder(View itemView) {
    super(itemView);
    mView = itemView;
    mIconView = (ImageView) mView.findViewById(R.id.user_image_profile);
    mAuthorView = (TextView) mView.findViewById(R.id.user_text_profile);
    mView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mListener.onUserClick();
        }
    });
}

public void setIcon(String url) {
    GlideUtil.loadProfileIcon(url, mIconView);//       
}

public void setPostClickListener(UserClickListener listener) {
    mListener = listener;
}


public void setText(final String text) {
    if (text == null || text.isEmpty()) {
        mAuthorView.setVisibility(View.GONE);
        return;
    } else {
        mAuthorView.setVisibility(View.VISIBLE);
        mAuthorView.setText(text);
        mAuthorView.setMaxLines(POST_TEXT_MAX_LINES);
    }
}

public interface UserClickListener {
    void onUserClick();
}
}

And here is my database call:

 private FirebaseRecyclerAdapter<Person, UserListViewHolder> getFirebaseRecyclerAdapter(Query query) {
    return new FirebaseRecyclerAdapter<Person, UserListViewHolder>(
            Person.class, R.layout.user_row_item, UserListViewHolder.class, query) {

        @Override
        protected void populateViewHolder(UserListViewHolder viewHolder, Person model, int position) {
            setupUser(viewHolder, model, position, null);
        }

    };
}

private void setupUser(final UserListViewHolder UserViewHolder, final Person user, final int position, final String inPostKey) {
    final String postKey;
    if (mAdapter instanceof FirebaseRecyclerAdapter) {
        postKey = ((FirebaseRecyclerAdapter) mAdapter).getRef(position).getKey();
    } else {
        postKey = inPostKey;
    }
    FirebaseUtil.getUsersRef().child(postKey).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(final DataSnapshot dataSnapshot) {
            UserViewHolder.setPostClickListener(new UserListViewHolder.UserClickListener() {
                @Override
                public void onUserClick() {
                    mGroup.addUserToGroup(dataSnapshot.getKey());
                }
            });
            UserViewHolder.setIcon(dataSnapshot.child("photoUrl").getValue(String.class));
            UserViewHolder.setText(dataSnapshot.child("displayName").getValue(String.class));

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}

You just need to set the image in the same way that you set your others values when retrieving data from Firebase, but using your already generated newURL for that image after upload it to the cloud.

Maybe you can find another way to just set the url, but I suggest you to keep it like another parameter in your custom object, being dynamic if you want to retrieve that data more than once even if you are not uploading the image.

Solution 2

There is already an official implementation for this purpose.

https://github.com/firebase/quickstart-android/tree/master/storage

The basic idea is to upload the image to the firebase storage and the store the image url to the database and then download it via this link.

In the MyDownloadService.java class mStorageRef.child(downloadPath).getStream method was used but i implemented with getBytes method not to deal with inputstreams. Because can load bytes with Glide easily. When the task is completed, it sends a broadcast intent with bytes as bundle. You can listen the broadcast receiver wherever u want in order to load ur image when it is downloaded.

public class DownloadService extends Service{

    private StorageReference mStorageRef;

    @Override
    public void onCreate() {
        super.onCreate();

        // Initialize Storage
        mStorageRef = FirebaseStorage.getInstance().getReference();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
     if (ACTION_DOWNLOAD.equals(intent.getAction())) {


        mStorage.child(downloadPath).getBytes(10*1024*1024).addOnSuccessListener(new OnSuccessListener<byte[]>() {
            @Override
            public void onSuccess(byte[] bytes) {
                Log.d(TAG, "download:SUCCESS " + bytes.length);

                // Send success broadcast with number of bytes downloaded
                Intent broadcast = new Intent(ACTION_COMPLETED);
                broadcast.putExtra(EXTRA_DOWNLOAD_BYTES, bytes);
                broadcast.putExtra(EXTRA_DOWNLOAD_INDEX, uid);
                LocalBroadcastManager.getInstance(getApplicationContext())
                        .sendBroadcast(broadcast);

                // Mark task completed
                taskCompleted();
            }
        }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception exception) {
                    Log.w(TAG, "download:FAILURE", exception);

                    // Send failure broadcast
                    Intent broadcast = new Intent(ACTION_ERROR);
                    broadcast.putExtra(EXTRA_DOWNLOAD_PATH, downloadPath);
                    LocalBroadcastManager.getInstance(getApplicationContext())
                    .sendBroadcast(broadcast);

                    // Mark task completed
                    taskCompleted();
                }
            });
    }

    }
Share:
16,574

Related videos on Youtube

hozdaman
Author by

hozdaman

Updated on September 14, 2022

Comments

  • hozdaman
    hozdaman over 1 year

    Hi I asked an earlier question about displaying an image using Base64 from my Firebase database. It was recommended to use firebase storage. I reworked my code and everything loads into the firebase storage and databse as it should. The issue I have is when I save the data nothing populates into my recyclerview. Everything is blank.

    Any help you can provide me to get this to work would be great. Thanks.

    EDIT: In my activity class I am calling a button clicklistener to activate the camera. Once the picture is taken it is saved to Firebase Storage. Then I download it the image from Storage and display it in a recyclerview. I understand the uploading portion but I am having difficulty understanding the downloading and displaying portion. Thanks.

    viewholder:bind method

    public void bind (ImageProgress progress){
    
        Glide.with(activity).load("").into(image);
     }
    }
    

    adapter

      @Override
    public ProgressViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
        return new ProgressViewHolder(activity, activity.getLayoutInflater().inflate(R.layout.weight_progress_list, parent, false));
    

    main activity class

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.weight_progress);
    
        saveButton = (Button) findViewById(R.id.saveButton);
        progressStatusEditText = (EditText) findViewById(R.id.progressStatusEditText);
        progressList = (RecyclerView) findViewById(R.id.progressList);
        mImageButton = (ImageButton) findViewById(R.id.takePictureButton);
        capturedImage=(ImageView)findViewById(R.id.capturedImageView);
    
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        progressList.setHasFixedSize(false);
        progressList.setLayoutManager(layoutManager);
    
        //take picture button
        mImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                openCamera();
            }
        });
    
    
        mDatabaseReference = database.getReference("Progress");
    
        saveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //get current user
                FirebaseUser user =FirebaseAuth.getInstance().getCurrentUser();
                String uid = user.getUid();
                ImageProgress progress = new ImageProgress(uid, progressStatusEditText.getText().toString());
                mDatabaseReference.push().setValue(progress);
                progressStatusEditText.setText("");
            }
        });
    }
    
    private void openCamera() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
    }
    
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
    
            Uri cameraImageURI = data.getData();
            //reference where images will be stored
            mStorageReference = storage.getReference("Progress Images");
            //reference to store file
            final StorageReference cameraImageRef = mStorageReference.child(cameraImageURI.getLastPathSegment());
            //upload to firebase storage
            cameraImageRef.putFile(cameraImageURI)
                    .addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
                        @Override
                        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                            Uri downloadUrl = taskSnapshot.getDownloadUrl();
                            progressStatusEditText.setText(downloadUrl.toString());
                        }
                    });
    }
    
    • hozdaman
      hozdaman
      @FrankvanPuffelen Hi Frank, I have edited my code to hopefully where my issue lies. I have added more description of what my issue is. Thanks in advance for you help.
    • Frank van Puffelen
      Frank van Puffelen
      Good to hear that you switched over to using Firebase Storage. That should scale a lot better. But there's too much code here for us to quickly help with. You seem to be uploading images, handling button clicks, reading from the database and much more. Reduce this to the minimum code that is needed to reproduce the problem and we'll have a better chance of being able to help you.
    • hozdaman
      hozdaman
      @FrankvanPuffelen Hi, I was wondering if you had a chance to look at my edited code? Thanks.
  • Erum
    Erum over 7 years
    Durdin can u pls help me , when i m uploading image on firebase then its sucessfully uploaded and as well as the uploaded image is shown twice in adapter in UI why ?
  • Brandon Zamudio
    Brandon Zamudio almost 7 years
    The recyclerview is recommended more than a listview for these purposes; anyway, if you are proposing some answer give at least little "how-to-do", or some links.