Нужно ли создавать 151 подключение к серверу при отображении 150 изображений в RecyclerView, хранящемся в папке «Изображения» Firebase Storage?

Предположим, у вас есть 150 изображений, хранящихся в папке изображений в вашем хранилище Firebase. Каждое изображение должно иметь название, которое будет вставлено в процессе загрузки. Теперь предположим, что вы хотите отобразить все эти изображения в RecyclerView. В этом сценарии вам потребуется создать 151 отдельное подключение к серверу вместо одного. Это может показаться нелогичным, поэтому позвольте мне объяснить.

Первое соединение — получение всех изображений с помощью следующей строки кода: FirebaseStorage.getInstance().getReference().child("Images/").listAll(). Это вернет список всех изображений в папке.

Для каждого изображения вам потребуется выполнить еще одно подключение к серверу, чтобы получить метаданные для этого изображения. Это означает, что для каждого отдельного изображения вам нужно будет сделать отдельный вызов на сервер, в результате чего будет установлено 151 соединение.

Вот предварительный просмотр кода для этого сценария:

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
}
});

Впрочем, вполне возможно, что я что-то упускаю. Это действительно так, или есть лучшее решение? Я не хочу называть изображение непосредственно именем файла, потому что я пробовал это раньше и обнаружил, что длины недостаточно.

Буду очень признателен за любые предложения или альтернативные решения этой проблемы. Заранее спасибо!

Кроме того, я хотел бы выразить благодарность OpenAI GPT-3 за помощь в написании этого четкого и лаконичного вопроса.

Используете ли вы Firebase Storage (поддерживающее правило безопасности) или хранилище Google Cloud напрямую только для подтверждения?

Dharmaraj 04.02.2023 12:35

@Dharmaraj Firebase Storage (в настоящее время без правил)

Taha Sami 04.02.2023 12:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете создать внутренний метод API, который возвращает список заголовков за один вызов.

Теперь я знаю, что ваш код был предназначен только для демонстрации, но....

  1. ваш код говорит task.getResult().getItems().get(0), что означает, что только первый элемент используется 150 раз

  2. Вызов task.getResult().getItems() внутри for означает, что вы вызываете что-то, что нужно вызвать только один раз 150 раз.

  3. Использование harcoded 150 вместо items.length не является хорошей идеей.

Когда вы видите, что ваш код громоздкий или трудный для чтения, следуйте «Единой ответственности», чтобы разделить его на более простые методы.

В приведенном ниже коде я использую тип «Item», потому что теперь я не знаю имя типа, возвращаемое 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 ;
}


Это не окончательный код, просто демонстрация общей идеи. Благодарю за ваш ответ.

Taha Sami 04.02.2023 13:00

Демонстрационный код не должен отвлекаться, в любом случае вам нужно разделить код на методы и убедиться, что после завершения задачи соединение будет закрыто.

Mauricio Gracia Gutierrez 04.02.2023 13:02
Ответ принят как подходящий

Прежде всего, FirebaseStorage.getInstance() — это синглтон, который всегда будет создавать один экземпляр.

Кроме того, хотя решение Mauricio Gracia Gutierrez будет работать, см. ниже решение, которое использует задачи Tasks#whenAllSuccess(Collection>):

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!
        }
    }
});

Таким образом, вы будете ждать, пока у вас не будет полного списка заголовков.

Я проверю ваш код завтра после того, как закончу свою работу. Если это сработает, я выберу ваш ответ как правильный. Также, пожалуйста, расскажите мне больше о whenAllSuccess. Спасибо.

Taha Sami 04.02.2023 13:33

Хорошо, попробуй и скажи мне, работает ли это. Tasks#whenAllSuccess(Collection> tasks), на мой взгляд, лучший способ решить эту проблему, когда вам приходится иметь дело с несколькими объектами Task.

Alex Mamo 04.02.2023 13:34

Я выберу ваш ответ как правильный, потому что я верю в ваше решение. Я проверю код позже, спасибо.

Taha Sami 04.02.2023 13:42

Я никогда не писал код для FirebaseStorage, рад видеть, что был рядом ;-)

Mauricio Gracia Gutierrez 05.02.2023 12:59

Другие вопросы по теме