Как выполнить 5 параллельных запросов за справочниками и дождаться всех результатов перед выходом из метода
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Параллельное выполнение запросов в 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")
}
}
Ключевые моменты реализации:
- coroutineScope - создает область видимости для корутин, которая завершится только когда все дочерние корутины завершатся
- async - запускает асинхронную операцию, возвращая
Deferred<T> - awaitAll() - ожидает завершения всех
Deferredопераций - 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
- Нужны сложные трансформации потоков данных
Важные аспекты реализации
- Управление потоками - все сетевые операции должны выполняться в фоновых потоках
- Обработка ошибок - решите, должен ли метод падать при первой ошибке или продолжать выполнение
- Таймауты - добавьте ограничение по времени выполнения:
suspend fun fetchWithTimeout(): List<Reference> = withTimeout(10000) {
fetchAllReferences()
}
- Отмена операций - обеспечьте возможность отмены при выходе из 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 является оптимальным выбором.