Suspend function — ay isang function na may suspend modifier na maaaring mag-pause ng pag-execute nito nang hindi hinaharangan ang thread at magpatuloy mamaya sa parehong coroutine. Ayon sa JetBrains Kotlin Docs, 2025, ang mga suspend function ay pangunahing bloke ng pagbuo ng mga coroutine, na nagbibigay ng asynchrony nang walang mga callback. Bawat suspend function ay naka-compile sa isang state machine na batay sa Continuation, na nagpapahintulot ng mahusay na pamamahala ng mga suspension point.
Mga Pangunahing Punto
Suspend function — ay isang function na idineklara gamit ang keyword na suspend na maaaring mag-pause ng pag-execute sa isa o higit pang mga punto nang hindi hinaharangan ang thread. Bawat pagtawag ng suspend function sa loob ng ibang suspend function ay potensyal na suspension point.
suspend fun fetchUserData(): User {
val response = httpClient.get("/user")
return parser.parse(response)
}
Isinasalin ng Kotlin compiler ang naturang function sa state machine. Bawat suspension point (pagtawag sa ibang suspend function) ay nagiging isang state (label). Ang kasalukuyang thread ay pinakawalan sa pagitan ng mga state, at pagkatapos makumpleto ang inaasahang operasyon, magpapatuloy ang pag-execute mula sa susunod na state.
Lumitaw ang mga suspend function sa Kotlin 1.3 (taong 2018) kasama ang mga coroutine bilang isang eksperimental na feature at naging stable sa Kotlin 1.5 (taong 2021). Bago ito, ang asynchrony sa Kotlin/Java ay ibinigay sa pamamagitan ng mga callback, RxJava at CompletableFuture. Nag-alok ang mga suspend function ng alternatibo na may linear syntax at awtomatikong pamamahala ng thread.
Ang pag-unawa sa panloob na istraktura ng mga suspend function ay susi sa tamang paggamit ng mga coroutine. Hindi tulad ng mga ordinaryong function, bawat suspend function ay naka-compile sa isang klase na may Continuation interface.
Nagdaragdag ang Kotlin compiler ng parameter na uri ng Continuation sa dulo ng bawat parameter ng suspend function. Ang Continuation ay naglalaman ng:
Ipagpalagay na mayroon tayong suspend function na may dalawang tawag sa iba pang suspend function:
suspend fun process() {
val a = stepOne()
val b = stepTwo(a)
println(b)
}
Ginagawa ito ng compiler sa state machine na may mga label:
// Pinasimpleng representasyon ng nabuong code
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
}
}
}
Mahalagang obserbasyon: kung ang function ay nagbalik ng COROUTINE_SUSPENDED, ang kasalukuyang thread ay pinakawalan. Kapag natapos ang asynchronous operation, tinatawag ang Continuation.resumeWith, at magpapatuloy ang state machine mula sa susunod na label.
Ang deklarasyon ng suspend function ay hindi naiiba sa ordinaryong function, maliban sa keyword na suspend bago ang fun. Mayroon lamang isang limitasyon: ang suspend function ay maaari lamang tawagin mula sa coroutine o ibang suspend function.
suspend fun delayAndReturn(ms: Long): String {
delay(ms)
return "Done after ${ms}ms"
}
Sa halimbawang ito, ang delay ay isa ring suspend function na nagpapa-pause ng coroutine para sa tinukoy na bilang ng millisecond nang hindi hinaharangan ang thread. Pagkatapos ng pagkaantala, magpapatuloy ang pag-execute.
fun main() = runBlocking {
val result = delayAndReturn(1000)
println(result)
}
Ang runBlocking ay lumilikha ng tulay sa pagitan ng ordinaryong mundo at mga coroutine. Sa loob ng lambda, pinapayagan ang pagtawag sa anumang suspend function.
Sinusuportahan ng Kotlin ang mga suspend na bersyon ng functional na uri — suspend () -> T at suspend (A) -> B. Ito ay nagpapahintulot sa pagpasa ng asynchronous lambda sa mga higher-order function:
suspend fun withRetry (
retries: Int = 3,
block: suspend () -> T
): T {
repeat(retries - 1) {
try { return block() }
catch (_: Exception) { delay(100) }
}
return block()
}
Ang function na withRetry ay tumatanggap ng suspend lambda at inuulit ang pag-execute nito kapag may mga error. Ito ay tipikal na pattern para sa mga network request na may mga pagsubok muli.
Ang mga pagkakaiba sa pagitan ng suspend at ordinaryong function ay lampas sa simpleng pagdaragdag ng modifier. Tingnan natin ang mga pangunahing pagkakaiba.
| Katangian | Ordinaryong function | Suspend function |
|---|---|---|
| Thread ng pag-execute | Hinaharangan ang thread hanggang matapos | Maaaring pakawalan ang thread at magpatuloy mamaya |
| Mga parameter ng compiler | Tanging tinukoy na mga parameter | Implicit Continuation sa dulo |
| Pagtawag mula sa ordinaryong function | Oo | Hindi |
| Stack | Pisikal na stack ng thread | State machine sa heap + pisikal na stack sa pagitan ng mga punto |
| Return | Direktang halaga | Halaga o COROUTINE_SUSPENDED |
| Pagganap | Minimal na overhead | ~ilang nanosecond para sa state machine (Kotlin 1.9+) |
Ang ordinaryong function ay walang Continuation — walang lugar upang i-save ang estado at ipagpatuloy ang pag-execute. Kung kailangan tumawag ng suspend function mula sa ordinaryong function, gamitin ang runBlocking (para sa pagsubok) o CoroutineScope.launch (para sa produksyon na isinasaalang-alang ang lifecycle).
Tingnan natin ang tatlong totoong sitwasyon ng paggamit ng mga suspend function sa Android app na may Kotlin.
Sinusuportahan ng Room ang mga suspend function nang direkta — ang query ay isinasagawa sa background nang awtomatiko:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: Int): User?
@Insert
suspend fun insertUser(user: User)
}
Gumagamit ang Room sa loob ng Dispatchers.IO para isagawa ang query, at ang resulta ay ibinabalik sa dispatcher kung saan tinawag ang suspend function.
class ProfileViewModel : ViewModel() {
private val repo = ProfileRepository()
fun loadProfile(id: String) {
viewModelScope.launch {
val profile = repo.getProfile(id)
_profile.value = profile
}
}
}
Ang ViewModelScope.launch ay lumilikha ng coroutine, sa loob nito ay tinatawag ang suspend function na getProfile. Pagkatapos makuha ang resulta, ang UI ay ina-update sa pangunahing thread.
suspend fun placeOrder(cart: Cart): OrderResult {
val validated = validateCart(cart)
val payment = processPayment(validated)
val receipt = sendReceipt(payment)
return receipt
}
Tatlong suspend function ang isinasagawa nang sunud-sunod. Sa bawat hakbang, ang coroutine ay maaaring huminto nang hindi hinaharangan ang thread. Kung ang isang hakbang ay nag-throw ng exception — ang iba ay hindi isinasagawa, na nagpoprotekta laban sa mga hindi wastong estado ng order.
Kahit na ang mga may karanasang Kotlin developer ay nagkakamali sa pagdidisenyo ng mga suspend function. Tingnan natin ang pinakakaraniwan.
Ang suspend function ay hindi ginagawang awtomatikong asynchronous ang code. Ang Thread.sleep(), InputStream.read(), at iba pang panawag na humaharang ay haharang pa rin sa thread. Gamitin ang withContext(Dispatchers.IO) para balutin ang mga operasyong humaharang.
Kung ang isang function ay hindi tumatawag sa ibang suspend function at hindi gumaganap ng asynchronous operations — ang suspend modifier ay kalabisan. Nagdaragdag ito ng overhead sa state machine at nililimitahan ang konteksto ng pagtawag. Gawing suspend lamang ang function kapag ito ay talagang nagpa-pause.
Kapag kinansela ang coroutine, ang mga suspend function ay nagh-throw ng CancellationException. Huwag itong hulihin nang walang pag-iisip — inaalis mo ang kakayahan ng tumatawag na code na wastong kumpletuhin ang pagkansela. Kung kailangan magsagawa ng finalizing operation, gamitin ang finally block at NonCancellable.
suspend fun safeOperation() {
try {
doWork()
} finally {
withContext(NonCancellable) {
cleanup()
}
}
}
Ang finally block ay palaging isinasagawa, kabilang ang pagkansela, at ginagarantiyahan ng NonCancellable na ang paglilinis ay hindi mapuputol.
Hindi maaaring tumawag ng suspend function nang direkta mula sa callback nang hindi gumagawa ng coroutine. Gamitin ang suspendCoroutine o suspendCancellableCoroutine para iakma ang callback style sa mga coroutine.
Mga Madalas Itanong
Oo, sa teknikal na paraan ang isang suspend function ay maaaring hindi tumawag ng ibang suspend function. Ang compiler ay gagawa ng state machine na may isang state (label 0). Gayunpaman, walang praktikal na pakinabang ang naturang function — ito ay isinasagawa tulad ng ordinaryong function, ngunit may overhead. Huwag gumamit ng suspend nang hindi kinakailangan.
Nagbibigay ang Kotlin ng kotlinx-coroutines-debug — isang library na may DebugProbes at mga tool sa pagsubaybay ng coroutine. Sa Android Studio simula sa bersyong Arctic Fox, mayroong built-in na Coroutines tab sa Debugger na nagpapakita ng mga aktibong coroutine, kanilang estado at mga suspension point.
Bawat suspension point ay lumilikha ng bagong state sa state machine. Para sa karamihan ng mga application, ang overhead ng isang punto ay nasa yunit ng nanosecond (Kotlin 1.9+). Lamang kapag may sampu-sampung libong puntos sa isang loop, ito ay nagkakahalaga ng pagsasama-sama ng mga operasyon o paggamit ng sequence/flow.
Sa Kotlin, ang suspend ay modifier ng uri ng function, hindi marker ng return value (tulad ng async sa C#). Anumang suspend function ay maaaring magkaroon ng anumang mga parameter at return type, at ang pagtawag nito ay syntactically hindi naiiba sa pagtawag ng ordinaryong function — walang await operator sa lugar ng pagtawag.
Gamitin ang suspendCancellableCoroutine para sa adaptasyon. Sa loob, ipinapasa mo ang pagpaparehistro ng callback na tumatawag sa continuation.resume() at nagbabalik ng cancellation token kung sinusuportahan ng callback ang pag-unsubscribe. Ito ay karaniwang pattern para sa pagbalot ng lumang Android API.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din