Как настраивать и использовать корутины в проектах на Kotlin?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Для настройки корутин необходимо добавить соответствующую зависимость в build.gradle файл.
// build.gradle (app module)
dependencies {
//... другие зависимости
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Для JVM, Android, JS, Native
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Для Android (если нужен Dispatchers.Main)
}
Использование корутин включает:
-
Область жизни (Scope): Определение области, в которой корутины будут выполняться и управлять своим жизненным циклом.
GlobalScope: Область жизни всего приложения, использовать осторожно, так как утечка памяти возможна.CoroutineScope: Создается явно, позволяет контролировать отмену корутин.- Предопределенные области в фреймворках (например,
lifecycleScopeв Android ViewModel).
// Пример с CoroutineScope val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // Создание Scope с Dispatcher и Job fun performBackgroundTask() { myScope.launch { // Запуск корутины // Долгий вычислительный процесс } } fun cancelAllTasks() { myScope.cancel() // Отмена всех корутин в Scope } -
Создатели корутин (Builders): Функции для запуска корутин.
launch: Запускает корутину, которая не возвращает результат явно (возвращаетJob).async: Запускает корутину, которая возвращает результат в видеDeferred.
import kotlinx.coroutines.* suspend fun fetchData() = coroutineScope { // coroutineScope - builder для структурированной конкурентности val data1 = async { networkCall1() } // async возвращает Deferred val data2 = async { networkCall2() } // ... обработка данных после их получения data1.await() // Получение результата от Deferred, вызывает усыпление корутины до завершения data2.await() } suspend fun networkCall1(): String { delay(1000) // Имитация сетевого запроса return "Data 1" } suspend fun networkCall2(): String { delay(1500) return "Data 2" } fun startFetching() = runBlocking { // runBlocking - builder для блокирования текущего потока (для main или тестов) launch { // launch возвращает Job println("Fetching data...") fetchData() println("Data fetched!") } } -
Диспетчеры (Dispatchers): Определяют, в каком потоке или пуле потоков будет выполняться корутина.
Dispatchers.Default: Для CPU-интенсивных задач.Dispatchers.IO: Для блокирующих I/O операций (файловый доступ, сеть).Dispatchers.Main: Основной поток (только для Android и Swing/JavaFX).Dispatchers.Unconfined: Запускает корутину в вызывающем потоке, усыпляется, а затем возобновляется в потоке, который возобновил выполнение.
import kotlinx.coroutines.* fun simpleTask() { GlobalScope.launch(Dispatchers.IO) { // Указание диспетчера // Выполнение I/O операции println("Running on thread: ${Thread.currentThread().name}") } } fun main() = runBlocking { launch(Dispatchers.Default) { println("Default thread: ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Unconfined thread 1: ${Thread.currentThread().name}") delay(100) // Усыпление println("Unconfined thread 2: ${Thread.currentThread().name}") // Возобновление в другом потоке (возможно) } delay(200) // Ждем завершения корутин } -
Приостанавливающие функции (Suspending functions): Функции, помеченные ключевым словом
suspend, которые могут быть приостановлены и возобновлены без блокирования потока. Могут вызываться только из других приостанавливающих функций или из блока корутины. -
Обработка отмены и исключений: Корутины поддерживают структурированную отмену и распространение исключений.
- Отмена:
import kotlinx.coroutines.* fun cancellableTask() = GlobalScope.launch { try { repeat(1000) { i -> println("Working $i ...") delay(100) // suspend function that respects cancellation } } catch (e: CancellationException) { println("Task was cancelled!") } finally { println("Cleaning up...") } } fun main() = runBlocking { val job = cancellableTask() delay(500) // Ждем немного job.cancelAndJoin() // Отменяем и ждем завершения } - Исключения: В случае
launch, неперехваченное исключение приведет к падению приложения (в Android по умолчанию). В случаеasync, исключение будет брошено при вызовеawait(). Для более гранулярного контроля используютсяCoroutineExceptionHandlerилиSupervisorJob.
import kotlinx.coroutines.* fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("Caught exception: $exception") } val job = GlobalScope.launch(handler) { // Применение обработчика throw IllegalStateException("Something went wrong") } job.join() // Ждем завершения } - Отмена: