Ответ
В Kotlin корутины создаются с помощью CoroutineScope и билдеров launch или async. Пример:
// Создание корутины в GlobalScope (не рекомендуется для production)
GlobalScope.launch {
// Код внутри корутины
delay(1000) // Неблокирующая задержка
println("Hello from coroutine!")
}
// Рекомендуемый способ - использование scope с жизненным циклом
class MyActivity : AppCompatActivity(), CoroutineScope by MainScope() {
fun startCoroutine() {
launch {
val result = async { fetchData() }.await()
updateUI(result)
}
}
override fun onDestroy() {
super.onDestroy()
cancel() // Отмена всех корутин при уничтожении Activity
}
}
Ключевые моменты:
- Используйте
Dispatchersдля указания потока (Main, IO, Default) launch- для fire-and-forget операцийasync- для операций с возвращаемым значением- Всегда управляйте жизненным циклом корутин
Ответ 18+ 🔞
Э, слушай, смотри. Короче, эти ваши корутины в Kotlin — штука, конечно, охуенная, но если начать без мозгов, то будет вам хиросима и нигерсраки, честно.
Вот смотри, самый простой способ накосячить — это тупо в GlobalScope запулиться. Типа:
GlobalScope.launch {
// Код внутри корутины
delay(1000) // Неблокирующая задержка
println("Hello from coroutine!")
}
Ну и что? А то, что эта корутина, сука, будет жить своей жизнью, пока приложение не сдохнет. Это как запустить таракана на кухне и забыть про него. Он там по своим делам ползает, а потом ты его через месяц находишь за холодильником — уже овердохуища тараканьего семейства. Так и тут: запустил и забыл, а она где-то там висит, память жрёт, и потом непонятно, кто её отменять должен. Доверия к такому подходу — ноль ебать.
Умные дяди говорят: используй scope с жизненным циклом. Вот как, бля, это выглядит на практике, в какой-нибудь Activity:
class MyActivity : AppCompatActivity(), CoroutineScope by MainScope() {
fun startCoroutine() {
launch {
val result = async { fetchData() }.await()
updateUI(result)
}
}
override fun onDestroy() {
super.onDestroy()
cancel() // Отмена всех корутин при уничтожении Activity
}
}
Вот это уже дело! Смотри, что происходит. Мы тут делегируемся к MainScope(), который, ядрёна вошь, сразу даёт нам диспетчер Main для UI-потока. Внутри launch мы можем спокойно запустить async, чтобы что-то там посчитать или с сети стянуть, а потом await() дождаться результата и обновить интерфейс. И самое главное — в onDestroy() мы вызываем cancel(). Всё! Все корутины, запущенные в этом scope, получат пиздюлей и дружно завершатся. Красота!
Ключевые моменты, которые надо в башке держать, а то подозрение ебать чувствую, что забудешь:
Dispatchers— это твои указатели, где работать.Main— для UI,IO— для сети или диска,Default— для тяжёлых вычислений. Не тычь всё вMain, а то интерфейс будет тормозить, как полупидор.launch— это типа "запустил и пошёл". Огненный шар кинул, а долетит он или нет — тебя не ебёт. Для операций без результата.async— это когда тебе нужен ответ. Кинул огненный шар, а он тебе через секунду вернётся с добычей. ВозвращаетDeferred, из которого потом результатawait()'ишь.- Жизненный цикл — это святое. Всегда привязывай корутины к чему-то, что само знает, когда ему конец. Активность, фрагмент, вью-модель — неважно. Чтобы когда компонент сдох, все его корутины накрылись медным тазом автоматически, а не висели в памяти, как призраки.
Вот и вся магия. Главное — не выёбывайся и делай по уму, а не как мартышлюшка с гранатой.