Suspend function — adalah fungsi dengan modifier suspend yang dapat menangguhkan eksekusinya tanpa memblokir thread dan melanjutkannya nanti di coroutine yang sama. Menurut JetBrains Kotlin Docs, 2025, fungsi suspend adalah blok bangunan fundamental coroutine, menyediakan asinkronisitas tanpa callback. Setiap fungsi suspend dikompilasi menjadi state machine berbasis Continuation, yang memungkinkan pengelolaan titik penangguhan secara efisien.
Poin Penting
Suspend function — adalah fungsi yang dideklarasikan dengan kata kunci suspend yang dapat menangguhkan eksekusi di satu atau lebih titik tanpa memblokir thread. Setiap pemanggilan fungsi suspend di dalam fungsi suspend lain adalah titik penangguhan potensial.
suspend fun fetchUserData(): User {
val response = httpClient.get("/user")
return parser.parse(response)
}
Compiler Kotlin menerjemahkan fungsi tersebut menjadi state machine. Setiap titik penangguhan (pemanggilan fungsi suspend lain) menjadi sebuah state (label). Thread saat ini dibebaskan di antara state, dan setelah operasi yang ditunggu selesai, eksekusi dilanjutkan dari state berikutnya.
Fungsi suspend muncul di Kotlin 1.3 (tahun 2018) bersama dengan coroutine sebagai fitur eksperimental dan menjadi stabil di Kotlin 1.5 (tahun 2021). Sebelumnya, asinkronisitas di Kotlin/Java disediakan melalui callback, RxJava, dan CompletableFuture. Fungsi suspend menawarkan alternatif dengan sintaks linier dan manajemen thread otomatis.
Memahami struktur internal fungsi suspend adalah kunci untuk bekerja dengan benar dengan coroutine. Tidak seperti fungsi biasa, setiap fungsi suspend dikompilasi menjadi kelas dengan antarmuka Continuation.
Compiler Kotlin menambahkan parameter bertipe Continuation di akhir setiap parameter fungsi suspend. Continuation berisi:
Misalkan kita memiliki fungsi suspend dengan dua pemanggilan ke fungsi suspend lain:
suspend fun process() {
val a = stepOne()
val b = stepTwo(a)
println(b)
}
Compiler mengubahnya menjadi state machine dengan label:
// Representasi kode yang dihasilkan secara sederhana
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
}
}
}
Pengamatan penting: jika fungsi mengembalikan COROUTINE_SUSPENDED, thread saat ini dibebaskan. Ketika operasi asinkron selesai, Continuation.resumeWith dipanggil, dan state machine melanjutkan dari label berikutnya.
Deklarasi fungsi suspend tidak berbeda dengan fungsi biasa, kecuali kata kunci suspend sebelum fun. Hanya ada satu batasan: fungsi suspend hanya dapat dipanggil dari coroutine atau fungsi suspend lain.
suspend fun delayAndReturn(ms: Long): String {
delay(ms)
return "Done after ${ms}ms"
}
Dalam contoh ini, delay juga merupakan fungsi suspend yang menangguhkan coroutine selama jumlah milidetik yang ditentukan tanpa memblokir thread. Setelah penundaan, eksekusi dilanjutkan.
fun main() = runBlocking {
val result = delayAndReturn(1000)
println(result)
}
runBlocking membuat jembatan antara dunia biasa dan coroutine. Di dalam lambda, pemanggilan fungsi suspend apa pun diperbolehkan.
Kotlin mendukung versi suspend dari tipe fungsional — suspend () -> T dan suspend (A) -> B. Ini memungkinkan pengiriman lambda asinkron ke fungsi tingkat tinggi:
suspend fun withRetry (
retries: Int = 3,
block: suspend () -> T
): T {
repeat(retries - 1) {
try { return block() }
catch (_: Exception) { delay(100) }
}
return block()
}
Fungsi withRetry menerima lambda suspend dan mengulangi eksekusinya saat terjadi kesalahan. Ini adalah pola umum untuk permintaan jaringan dengan percobaan ulang.
Perbedaan antara fungsi suspend dan biasa melampaui sekadar penambahan modifier. Mari lihat perbedaan mendasarnya.
| Karakteristik | Fungsi biasa | Fungsi suspend |
|---|---|---|
| Thread eksekusi | Memblokir thread hingga selesai | Dapat membebaskan thread dan melanjutkan nanti |
| Parameter compiler | Hanya parameter yang ditentukan | Continuation implisit di akhir |
| Panggilan dari fungsi biasa | Ya | Tidak |
| Stack | Stack fisik thread | State machine di heap + stack fisik antar titik |
| Return | Nilai langsung | Nilai atau COROUTINE_SUSPENDED |
| Kinerja | Overhead minimal | ~beberapa nanodetik untuk state machine (Kotlin 1.9+) |
Fungsi biasa tidak memiliki Continuation — tidak ada tempat untuk menyimpan status dan melanjutkan eksekusi. Jika perlu memanggil fungsi suspend dari fungsi biasa, gunakan runBlocking (untuk pengujian) atau CoroutineScope.launch (untuk produksi dengan mempertimbangkan siklus hidup).
Mari lihat tiga skenario nyata penggunaan fungsi suspend di aplikasi Android dengan Kotlin.
Room mendukung fungsi suspend secara langsung — kueri dijalankan di latar belakang secara otomatis:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: Int): User?
@Insert
suspend fun insertUser(user: User)
}
Room secara internal menggunakan Dispatchers.IO untuk menjalankan kueri, dan hasilnya dikembalikan ke dispatcher tempat fungsi suspend dipanggil.
class ProfileViewModel : ViewModel() {
private val repo = ProfileRepository()
fun loadProfile(id: String) {
viewModelScope.launch {
val profile = repo.getProfile(id)
_profile.value = profile
}
}
}
ViewModelScope.launch membuat coroutine, di dalamnya fungsi suspend getProfile dipanggil. Setelah mendapatkan hasil, UI diperbarui di thread utama.
suspend fun placeOrder(cart: Cart): OrderResult {
val validated = validateCart(cart)
val payment = processPayment(validated)
val receipt = sendReceipt(payment)
return receipt
}
Tiga fungsi suspend dijalankan secara berurutan. Di setiap langkah, coroutine dapat berhenti tanpa memblokir thread. Jika suatu langkah melempar pengecualian — langkah lainnya tidak dijalankan, yang melindungi dari status pesanan yang tidak valid.
Bahkan pengembang Kotlin berpengalaman pun membuat kesalahan saat merancang fungsi suspend. Mari lihat yang paling umum.
Fungsi suspend tidak membuat kode secara otomatis asinkron. Thread.sleep(), InputStream.read(), dan panggilan memblokir lainnya tetap akan memblokir thread. Gunakan withContext(Dispatchers.IO) untuk membungkus operasi memblokir.
Jika suatu fungsi tidak memanggil fungsi suspend lain dan tidak melakukan operasi asinkron — modifier suspend berlebihan. Ini menambah overhead pada state machine dan membatasi konteks pemanggilan. Buat fungsi suspend hanya jika fungsi tersebut benar-benar ditangguhkan.
Saat pembatalan coroutine, fungsi suspend melempar CancellationException. Jangan menangkapnya tanpa berpikir — Anda menghilangkan kemampuan kode pemanggil untuk menyelesaikan pembatalan dengan benar. Jika perlu melakukan operasi finalisasi, gunakan blok finally dan NonCancellable.
suspend fun safeOperation() {
try {
doWork()
} finally {
withContext(NonCancellable) {
cleanup()
}
}
}
Blok finally selalu dijalankan, termasuk saat pembatalan, dan NonCancellable memastikan pembersihan tidak terputus.
Fungsi suspend tidak dapat dipanggil langsung dari callback tanpa membuat coroutine. Gunakan suspendCoroutine atau suspendCancellableCoroutine untuk mengadaptasi gaya callback ke coroutine.
Pertanyaan yang Sering Diajukan
Ya, secara teknis fungsi suspend bisa tidak memanggil fungsi suspend lain. Compiler akan membuat state machine dengan satu state (label 0). Namun, fungsi seperti itu tidak memiliki manfaat praktis — ia dijalankan seperti fungsi biasa, tetapi dengan overhead. Jangan gunakan suspend tanpa kebutuhan.
Kotlin menyediakan kotlinx-coroutines-debug — pustaka dengan DebugProbes dan alat pelacakan coroutine. Di Android Studio mulai versi Arctic Fox, ada tab Coroutines bawaan di Debugger yang menampilkan coroutine aktif, status, dan titik penangguhannya.
Setiap titik penangguhan membuat state baru di state machine. Untuk sebagian besar aplikasi, overhead satu titik adalah satuan nanodetik (Kotlin 1.9+). Hanya jika ada puluhan ribu titik dalam satu loop, ada baiknya menggabungkan operasi atau menggunakan sequence/flow.
Di Kotlin, suspend adalah modifier tipe fungsi, bukan penanda nilai kembali (seperti async di C#). Fungsi suspend apa pun dapat memiliki parameter dan tipe kembali apa pun, dan pemanggilannya secara sintaks tidak berbeda dengan pemanggilan fungsi biasa — tidak ada operator await di tempat pemanggilan.
Gunakan suspendCancellableCoroutine untuk adaptasi. Di dalamnya, Anda memberikan pendaftaran callback yang memanggil continuation.resume() dan mengembalikan token pembatalan jika callback mendukung pembatalan langganan. Ini adalah pola standar untuk membungkus API Android lama.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga