skip to Main Content

Suppose you have 150 images stored in the images folder within your Firebase Storage. Each image should have a title, which will be inserted during the uploading process. Now, let’s say you want to display all of these images in a RecyclerView. In this scenario, you would need to create 151 separate connections to the server instead of just one. This may seem counterintuitive, so allow me to explain.

The first connection is to retrieve all the images using the following line of code: FirebaseStorage.getInstance().getReference().child("Images/").listAll(). This will return a list of all the images in the folder.

For each image, you would need to make another connection to the server to retrieve the metadata for that image. This means that for every single image, you would need to make a separate call to the server, resulting in a total of 151 connections.

Here is a preview of the code for this scenario:

FirebaseStorage.getInstance().getReference().child("Images/").listAll().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
    for (int i = 0; i < 150; i++) {
        task.getResult().getItems().get(0).getMetadata().addOnCompleteListener(task1 -> {
            if (task1.isSuccessful()) {
                task1.getResult().getCustomMetadata("title"); //Finally I got the image title that stored inside image, it is cumbersome process.
            } else {
                //Handle error
            }
        });
    }
} else {
    //Handle error
}
});

However, it’s possible that I may be missing something. Is this really the way it works, or is there a better solution? I don’t want to name the image directly as the file name because I’ve tried that before and found that the length is not enough.

I would greatly appreciate any suggestions or alternative solutions to this problem. Thank you in advance!

Additionally, I would like to express my gratitude to OpenAI’s GPT-3 for helping me write this clear and concise question.

2

Answers


  1. You can create a backend API method that returns the list of titles for you in a single call

    I know now that your code was demostration purposes only but….

    1. your code says task.getResult().getItems().get(0) meaning that only the first item is being used 150 times

    2. Calling task.getResult().getItems() inside the for, means that you are calling something that only needs to be called once 150 times

    3. Using harcoded 150 instead of the items.length is not a good idea

    When you see that your code cumbersome or hard to read, follow the "Single Responsability" to split it into simpler methods.

    In the code below I’m using type "Item" because I dont now the name of the type returned by task.getResult().getItems()

    
    void getAllImagesMetadata() {
        FirebaseStorage.getInstance().getReference().child("Images/").listAll().addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            Item []items = task.getResult().getItems() ;
    
            for (int i = 0; i < items.length ; i++) {
                title[i] = getTitle(items[i] ; 
            }
        } else {
            //Handle error
        }
    
        // Make sure the connection to get list of all items is closed here
    }
    
    
    string getTitle(Item item) {
        string title ;
    
        item.getMetadata().addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            title = task.getResult().getCustomMetadata("title"); 
        } else {
            //Handle error
        }
        
        // Make sure the connection to get the metada is closed here
        return title ;
    }
    
    
    
    Login or Signup to reply.
  2. First of all, FirebaseStorage.getInstance() is a singleton, which will always create a single instance.

    Furthermore, while Mauricio Gracia Gutierrez’s will work, please see below a solution that uses Tasks#whenAllSuccess(Collection> tasks):

    StorageReference imagesRef = FirebaseStorage.getInstance().getReference().child("Images/");
    imagesRef.listAll().addOnCompleteListener(new OnCompleteListener<ListResult>() {
        @Override
        public void onComplete(@NonNull Task<ListResult> task) {
            if (task.isSuccessful()) {
                List<StorageReference> storageReferenceList = task.getResult().getItems();
                List<Task<StorageMetadata>> tasks = new ArrayList<>();
                storageReferenceList.forEach(item ->
                        tasks.add(item.getMetadata())
                );
                Tasks.whenAllSuccess(tasks).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
                    @Override
                    public void onSuccess(List<Object> objects) {
                        for (Object object : objects) {
                            String title = ((StorageMetadata) object).getCustomMetadata("title");
                            Log.d("TAG", title);
                        }
                    }
                });
            } else {
                Log.d(TAG, task.getException().getMessage()); //Never ignore potential errors!
            }
        }
    });
    

    In this way, you’ll wait until you have a List full of titles.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search