← Назад к вопросам

Как выполнить 5 параллельных запросов за справочниками и дождаться всех результатов перед выходом из метода

2.7 Senior🔥 191 комментариев
#Многопоточность и асинхронность#Сетевое взаимодействие

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Параллельное выполнение запросов в Android

Для выполнения 5 параллельных запросов за справочниками с ожиданием всех результатов в Android существует несколько подходов, каждый со своими преимуществами и сценариями использования. Основные варианты включают использование CoroutineScope с async/await, CompletableFuture и RxJava.

Основной подход: Kotlin Coroutines

Наиболее современный и рекомендованный способ - использование Kotlin Coroutines:

suspend fun fetchAllReferences(): Map<String, Result> = coroutineScope {
    val deferredResults = listOf(
        async { fetchReference1() },
        async { fetchReference2() },
        async { fetchReference3() },
        async { fetchReference4() },
        async { fetchReference5() }
    )
    
    deferredResults.awaitAll()
        .mapIndexed { index, result -> "ref${index + 1}" to result }
        .toMap()
}

private suspend fun fetchReference1(): Result {
    return withContext(Dispatchers.IO) {
        // Выполнение сетевого запроса или работы с БД
        delay(1000) // Имитация долгой операции
        Result.success("Данные справочника 1")
    }
}

Ключевые моменты реализации:

  1. coroutineScope - создает область видимости для корутин, которая завершится только когда все дочерние корутины завершатся
  2. async - запускает асинхронную операцию, возвращая Deferred<T>
  3. awaitAll() - ожидает завершения всех Deferred операций
  4. withContext(Dispatchers.IO) - переключает контекст на потоковый пул для IO-операций

Расширенный вариант с обработкой ошибок

suspend fun fetchReferencesWithErrorHandling(): List<Result<Reference>> = supervisorScope {
    val references = listOf("users", "products", "categories", "settings", "locations")
    
    references.map { refName ->
        async {
            try {
                Result.success(fetchReference(refName))
            } catch (e: Exception) {
                Result.failure(e)
            }
        }
    }.awaitAll()
}

Альтернативные подходы

Использование CompletableFuture (для Java-кода или смешанных проектов)

public Map<String, Reference> fetchAllReferences() throws ExecutionException, InterruptedException {
    CompletableFuture<Reference> future1 = CompletableFuture.supplyAsync(() -> fetchReference1());
    CompletableFuture<Reference> future2 = CompletableFuture.supplyAsync(() -> fetchReference2());
    CompletableFuture<Reference> future3 = CompletableFuture.supplyAsync(() -> fetchReference3());
    CompletableFuture<Reference> future4 = CompletableFuture.supplyAsync(() -> fetchReference4());
    CompletableFuture<Reference> future5 = CompletableFuture.supplyAsync(() -> fetchReference5());
    
    CompletableFuture<Void> allFutures = CompletableFuture.allOf(
        future1, future2, future3, future4, future5
    );
    
    allFutures.get(); // Ожидаем завершения всех
    
    Map<String, Reference> results = new HashMap<>();
    results.put("ref1", future1.get());
    results.put("ref2", future2.get());
    results.put("ref3", future3.get());
    results.put("ref4", future4.get());
    results.put("ref5", future5.get());
    
    return results;
}

Использование RxJava

fun fetchReferencesRx(): Single<List<Reference>> {
    return Observable.merge(
        fetchReference1Rx().toObservable(),
        fetchReference2Rx().toObservable(),
        fetchReference3Rx().toObservable(),
        fetchReference4Rx().toObservable(),
        fetchReference5Rx().toObservable()
    )
    .toList()
    .subscribeOn(Schedulers.io())
}

Рекомендации по выбору подхода

  • Kotlin Coroutines - предпочтительный выбор для новых проектов на Kotlin:

    • Более читаемый и простой код
    • Интеграция с Android Architecture Components
    • Меньше накладных расходов по памяти
    • Поддержка structured concurrency
  • CompletableFuture - используйте если:

    • Работаете с legacy Java-кодом
    • Требуется интеграция с Java-библиотеками
  • RxJava - подходит если:

    • В проекте уже используется ReactiveX
    • Нужны сложные трансформации потоков данных

Важные аспекты реализации

  1. Управление потоками - все сетевые операции должны выполняться в фоновых потоках
  2. Обработка ошибок - решите, должен ли метод падать при первой ошибке или продолжать выполнение
  3. Таймауты - добавьте ограничение по времени выполнения:
suspend fun fetchWithTimeout(): List<Reference> = withTimeout(10000) {
    fetchAllReferences()
}
  1. Отмена операций - обеспечьте возможность отмены при выходе из Activity/Fragment

Паттерны для ViewModel (MVVM)

class ReferencesViewModel : ViewModel() {
    private val _referencesState = MutableStateFlow<ReferencesState>(ReferencesState.Loading)
    val referencesState: StateFlow<ReferencesState> = _referencesState
    
    fun loadReferences() {
        viewModelScope.launch {
            _referencesState.value = ReferencesState.Loading
            try {
                val results = fetchAllReferences()
                _referencesState.value = ReferencesState.Success(results)
            } catch (e: Exception) {
                _referencesState.value = ReferencesState.Error(e.message)
            }
        }
    }
}

Выбор конкретной реализации зависит от архитектуры проекта, уже используемых библиотек и требований к обработке ошибок. Для большинства современных Android - приложений Kotlin Coroutines является оптимальным выбором.

Как выполнить 5 параллельных запросов за справочниками и дождаться всех результатов перед выходом из метода | PrepBro