Suspend function — je funkce s modifikátorem suspend, která může pozastavit své provádění bez blokování vlákna a později pokračovat ve stejné korutině. Podle JetBrains Kotlin Docs, 2025 jsou suspend funkce základním stavebním kamenem korutin, poskytujícím asynchronnost bez callbacků. Každá suspend funkce je kompilována do stavového stroje založeného na Continuation, což umožňuje efektivní správu bodů pozastavení.
Hlavní body
Suspend function — je funkce deklarovaná klíčovým slovem suspend, která může pozastavit provádění v jednom nebo více bodech bez blokování vlákna. Každé volání suspend funkce uvnitř jiné suspend funkce je potenciální bod pozastavení.
suspend fun fetchUserData(): User {
val response = httpClient.get("/user")
return parser.parse(response)
}
Kompilátor Kotlin překládá takovou funkci do stavového stroje. Každý bod pozastavení (volání jiné suspend funkce) se stává stavem (label). Aktuální vlákno je uvolněno mezi stavy a po dokončení očekávané operace provádění pokračuje od následujícího stavu.
Suspend funkce se objevily v Kotlin 1.3 (2018) spolu s korutinami jako experimentální funkce a staly se stabilními v Kotlin 1.5 (2021). Před tím byla asynchronnost v Kotlin/Java zajišťována pomocí callbacků, RxJava a CompletableFuture. Suspend funkce nabídly alternativu s lineární syntaxí a automatickým řízením vláken.
Porozumění vnitřní struktuře suspend funkcí je klíčem ke správné práci s korutinami. Na rozdíl od běžných funkcí je každá suspend funkce kompilována do třídy s rozhraním Continuation.
Kompilátor Kotlin přidává parametr typu Continuation na konec každého parametru suspend funkce. Continuation obsahuje:
Předpokládejme, že máme suspend funkci se dvěma voláními jiných suspend funkcí:
suspend fun process() {
val a = stepOne()
val b = stepTwo(a)
println(b)
}
Kompilátor ji převede na stavový stroj s nálepkami:
// Zjednodušená reprezentace vygenerovaného kódu
fun process(cont: Continuation<Unit>): Any? {
val cont = cont as ProcessContinuation
when (cont.label) {
0 -> {
cont.label = 1
if (stepOne(cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
}
1 -> {
cont.label = 2
val a = cont.result as TypeA
if (stepTwo(a, cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
}
2 -> {
println(cont.result)
Unit
}
}
}
Klíčové pozorování: pokud funkce vrátí COROUTINE_SUSPENDED, aktuální vlákno je uvolněno. Po dokončení asynchronní operace je zavoláno Continuation.resumeWith a stavový stroj pokračuje od dalšího labelu.
Deklarace suspend funkce se neliší od běžné, kromě klíčového slova suspend před fun. Existuje pouze jedno omezení: suspend funkci lze volat pouze z korutiny nebo jiné suspend funkce.
suspend fun delayAndReturn(ms: Long): String {
delay(ms)
return "Done after ${ms}ms"
}
V tomto příkladu je delay také suspend funkce, která pozastaví korutinu na zadaný počet milisekund bez blokování vlákna. Po zpoždění je provádění obnoveno.
fun main() = runBlocking {
val result = delayAndReturn(1000)
println(result)
}
runBlocking vytváří most mezi běžným světem a korutinami. Uvnitř lambdy je povoleno volání libovolných suspend funkcí.
Kotlin podporuje suspend verze funkčních typů — suspend () -> T a suspend (A) -> B. To umožňuje předávat asynchronní lambdy funkcím vyššího řádu:
suspend fun withRetry (
retries: Int = 3,
block: suspend () -> T
): T {
repeat(retries - 1) {
try { return block() }
catch (_: Exception) { delay(100) }
}
return block()
}
Funkce withRetry přijímá suspend lambdu a opakuje její provádění při chybách. Toto je typický vzor pro síťové požadavky s opakováním.
Rozdíly mezi suspend a běžnými funkcemi přesahují prosté přidání modifikátoru. Podívejme se na zásadní rozdíly.
| Charakteristika | Běžná funkce | Suspend funkce |
|---|---|---|
| Vlákno provádění | Blokuje vlákno do dokončení | Může uvolnit vlákno a pokračovat později |
| Parametry kompilátoru | Pouze uvedené parametry | Implicitní Continuation na konci |
| Volání z běžné funkce | Ano | Ne |
| Zásobník | Fyzický zásobník vlákna | Stavový stroj na haldě + fyzický zásobník mezi body |
| Návrat | Přímá hodnota | Hodnota nebo COROUTINE_SUSPENDED |
| Výkon | Minimální režie | ~pár nanosekund na stavový stroj (Kotlin 1.9+) |
Běžná funkce nemá Continuation — nemá kam uložit stav a čím obnovit provádění. Pokud potřebujete zavolat suspend funkci z běžné, použijte runBlocking (pro testy) nebo CoroutineScope.launch (pro produkci s ohledem na životní cyklus).
Podívejme se na tři reálné scénáře použití suspend funkcí v Android aplikacích v Kotlin.
Room přímo podporuje suspend funkce — dotaz se provádí automaticky na pozadí:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: Int): User?
@Insert
suspend fun insertUser(user: User)
}
Room interně používá Dispatchers.IO pro provedení dotazu a výsledek je vrácen dispečerovi, ve kterém byla suspend funkce zavolána.
class ProfileViewModel : ViewModel() {
private val repo = ProfileRepository()
fun loadProfile(id: String) {
viewModelScope.launch {
val profile = repo.getProfile(id)
_profile.value = profile
}
}
}
ViewModelScope.launch vytváří korutinu, uvnitř které je volána suspend funkce getProfile. Po získání výsledku je UI aktualizováno na hlavním vlákně.
suspend fun placeOrder(cart: Cart): OrderResult {
val validated = validateCart(cart)
val payment = processPayment(validated)
val receipt = sendReceipt(payment)
return receipt
}
Tři suspend funkce se provádějí sekvenčně. V každém kroku se korutina může zastavit bez blokování vlákna. Pokud některý krok vyvolá výjimku — ostatní se neprovedou, což chrání před nesprávnými stavy objednávky.
Dokonce i zkušení vývojáři Kotlin dělají chyby při navrhování suspend funkcí. Podívejme se na nejčastější.
Suspend funkce nedělá kód automaticky asynchronním. Thread.sleep(), InputStream.read() a další blokující volání stále zablokují vlákno. Použijte withContext(Dispatchers.IO) pro zabalení blokujících operací.
Pokud funkce nevolá jiné suspend funkce a neprovádí asynchronní operace — modifikátor suspend je nadbytečný. Přidává režii na stavový stroj a omezuje kontext volání. Dělejte funkci suspend pouze tehdy, když se skutečně pozastavuje.
Při zrušení korutiny suspend funkce vyvolávají CancellationException. Nechytejte ho bezmyšlenkovitě — připravujete volající kód o možnost správně dokončit zrušení. Pokud potřebujete provést finalizující operaci, použijte blok finally a NonCancellable.
suspend fun safeOperation() {
try {
doWork()
} finally {
withContext(NonCancellable) {
cleanup()
}
}
}
Blok finally se vždy provede, včetně zrušení, a NonCancellable zaručuje, že čištění nebude přerušeno.
Nelze volat suspend funkci přímo z callbacku bez vytvoření korutiny. Použijte suspendCoroutine nebo suspendCancellableCoroutine pro adaptaci callback stylu na korutiny.
Často kladené otázky
Ano, technicky suspend funkce nemusí volat jiné suspend funkce. Kompilátor vytvoří stavový stroj s jedním stavem (label 0). Taková funkce však nemá praktický užitek — provádí se jako běžná, ale s režií. Nepoužívejte suspend zbytečně.
Kotlin poskytuje kotlinx-coroutines-debug — knihovnu s DebugProbes a nástroji pro sledování korutin. V Android Studio od verze Arctic Fox je vestavěná karta Coroutines v Debuggeru, která zobrazuje aktivní korutiny, jejich stav a body pozastavení.
Každý bod pozastavení vytváří nový stav ve stavovém stroji. Pro většinu aplikací je režie jednoho bodu v jednotkách nanosekund (Kotlin 1.9+). Teprve při desítkách tisíc bodů ve smyčce stojí za to kombinovat operace nebo použít sequence/flow.
V Kotlin je suspend modifikátor typu funkce, nikoli označení návratové hodnoty (jako async v C#). Libovolná suspend funkce může mít libovolné parametry a návratový typ a její volání se syntakticky neliší od volání běžné funkce — na místě volání není operátor await.
Použijte suspendCancellableCoroutine pro adaptaci. Uvnitř předáte registraci callbacku, která volá continuation.resume(), a vrátíte token zrušení, pokud callback podporuje odhlášení. Toto je standardní vzor pro zabalení starých Android API.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také