Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Android

Concurrency dan Coroutines pada Kotlin

Difficulty:IntermediateLength:MediumLanguages:

Indonesian (Bahasa Indonesia) translation by Nur Rohman (you can also view the original English article)

Java Virtual Machine, atau disingkat dengan JVM, tealh mendukung multithreading. Setiap proses yang Anda jalankan di dalamnya bebas untuk membuat sejumlah thread yang wajar untuk melakukan banyak tugas secara asynchronous. Namun, menulis kode yang bisa melakukannya dengan cara yang optimal dan bebas dari kesalahan bisa dibilang sangat sulit. Selama bertahun-tahun, Java, bahasa JVM lainnya, dan banyak library pihak ketiga telah mencoba menghadirkan pendekatan kreatif dan elegan untuk mengatasi masalah ini.

Misalnya, Java 5 memperkenalkan executor framework, yang memungkinkan Anda untuk memisahkan detail manajemen thread dari logika bisnis Anda. Java 8 menawarkan parallel streams, yang dapat dengan mudah digunakan dengan lambda expressions. RxJava membawa reactive extensions ke Java, yang memungkinkan Anda menulis kode asynchronous yang ringkas dan mudah dibaca.

Kotlin mendukung hampir semua pendekatan tersebut dan menawarkan beberapa pilihannya sendiri. Dalam tutorial ini, saya akan menunjukkan bagaimana Anda bisa menggunakannya di aplikasi Android.

Prasyarat

Untuk dapat mengikuti tutorial ini, Anda memerlukan:

Jika Anda belum familiar dengan lambda expression dan SAM interfaces, saya sarankan Anda juga membaca tutorial berikut sebelum melanjutkan:

Anda juga dapat mempelajari semua seluk beluk bahasa Kotlin dalam seri Kotlin From Scratch kami.

1. Membuat Threads

Biasanya, contoh dari kelas yang mengimplementasikan interface Runnable digunakan untuk membuat thread di Kotlin. Karena antarmuka Runnable hanya memiliki satu metode, metode run(), Anda dapat memanfaatkan fitur konversi SAM Kotlin's untuk membuat thread baru dengan mengurangi kode boilerplate.

Berikut adalah bagaimana Anda dapat menggunakan fungsi thread(), yang merupakan bagian dari Kotlin's standard library, untuk mempercepat dalam membuat dan memulai thread baru:

Pendekatan di atas hanya sesuai bila Anda perlu sesekali menghasilkan satu atau dua thread. Jika concurrency adalah bagian penting dari logika bisnis aplikasi Anda dan Anda memerlukan sejumlah besar thread, menggunakan thread pools dengan executor service adalah ide yang lebih baik.

Sebagai contoh, kode berikut menggunakan metode newFixedThreadPool() dari kelas Executors untuk membuat thread pools yang berisi 8 (delapan) thread yang dapat digunakan kembali dan menjalankan sejumlah besar backround operations di dalamnya:

Ini mungkin tidak jelas pada pandangan pertama, tapi dalam kode di atas, argumen untuk metode submit() dari executor service adalah benar-benar sebuah objek Runnable.

2. Mendapatkan Hasil dari Threads

Background tasks dibuat menggunakan interface Runnable dan tidak menghasilkan apapun secara langsung. Jika Anda ingin untuk menerima hasil dari thread Anda, Anda harus menggunakan interface Callable sebagai gantinya, yang juga merupakan interface SAM.

Bila Anda melewati objek Callable ke dalam metode submit() dari executor service, Anda akan menerima objek Future. Seperti namanya, objek Future akan berisi hasil dari Callable di beberapa poin kedepannya, ketika executor service telah selesai menjalankannya. Untuk mendapatkan hasil sebenarnya dari objek Future, yang perlu Anda lakukan hanyalah memanggil metode get()- tapi hati-hati, thread Anda akan diblokir jika Anda memanggilnya sebelum waktunya.

Contoh kode berikut menunjukkan cara membuat objek yang dapat dipanggil dan mengembalikan Future dengan tipe String, jalankan, dan cetak hasilnya:

3. Sinkronisasi Threads

Tidak seperti Java, Kotlin tidak memiliki kata kunci synchronized. Oleh karena itu, untuk menyinkronkan beberapa background operation, Anda diharapkan menggunakan anotasi @Synchronized atau fungsi inline library standar synchronized(). Anotasi dapat menyinkronkan seluruh metode, dan fungsi yang bekerja pada blok pernyataan.

Anotasi @Synchronized dan fungsi synchronized() menggunakan konsep monitor locks.

Jika Anda belum tahu, setiap objek di JVM memiliki monitor yang terkait dengannya. Untuk saat ini, Anda bisa menganggap monitor sebagai token khusus yang bisa diperoleh, atau dikunci, untuk mendapatkan akses eksklusif ke objek. Setelah monitor objek terkunci, thread lain yang ingin bekerja pada objek harus menunggu sampai monitor dilepaskan, atau tidak terkunci lagi.

Sementara anotasi @Synchronized mengunci monitor objek yang diasosiasikan dengan metode yang terkait, fungsi synchronized() dapat mengunci monitor dari setiap objek yang dilewatkan kepadanya sebagai argumen.

4. Memahami Coroutines

Melalui sebuah experimental library, Kotlin menawarkan pendekatan alternatif untuk mencapai concurrency: coroutines. Coroutines jauh lebih ringan daripada thread dan lebih mudah dikelola.

Dalam aplikasi multithreaded mobile, thread biasanya digunakan untuk operasi seperti mengambil informasi dari internet atau query database. Operasi semacam itu tidak melibatkan banyak perhitungan, dan thread akan menghabiskan sebagian besar masa aktifnya dalam keadaan tersumbat, hanya menunggu data datang dari tempat lain. Seperti yang mungkin bisa Anda katakan, itu bukan cara yang sangat efisien untuk menggunakan CPU.

Coroutines dirancang untuk digunakan sebagai pengganti thread untuk operasi semacam itu. Hal terpenting yang perlu Anda pahami tentang coroutines adalah bahwa coroutines dapat disuspend. Dengan kata lain, alih-alih menghalangi, mereka bisa berhenti saat diperlukan dan terus berlanjut nantinya. Hal ini menyebabkan utilisasi CPU jauh lebih baik. Memang, dengan coroutines yang dirancang dengan baik, Anda bisa dengan mudah menjalankan lusinan background operations.

Untuk dapat menggunakan coroutines dalam proyek Android Studio Anda, pastikan Anda menambahkan dependensi berikut dalam modul app pada file build.gradle:

5. Membuat Suspending Functions

Coroutine dapat disuspend hanya dengan bantuan fungsi suspending. Oleh karena itu, sebagian besar coroutines telah memanggil setidaknya satu fungsi di dalamnya.

Untuk membuat fungsi suspending, yang perlu Anda lakukan adalah menambahkan modifier suspend ke dalam sebuah regular function. Berikut adalah contoh kode dari fungsi suspending yang mengeksekusi permintaan HTTP GET yang menggunakan library khttp:

Perhatikan bahwa fungsi suspend hanya dapat dipanggil oleh coroutine atau fungsi suspend lainnya. Jika Anda mencoba memanggilnya dari fungsi lain, kode Anda akan gagal dikompilasi.

6. Membuat Coroutines

Ketika membuat coroutine baru, Kotlin's standard library memiliki cukup banyak coroutine builder untuk membuat Anda merasa dimanja oleh beberapa pilihan. Coroutine builder paling sederhana yang dapat Anda gunakan adalah fungsi launch(), dan seperti kebanyakan coroutine builder lainnya, mengharapkan sebuah suspending lambda, yang tidak lain hanyalah sebuah fungsi suspending anonim. Dengan demikian, lambda ini adalah apa yang menjadi coroutine.

Kode berikut menciptakan coroutine yang membuat dua panggilan sekuensial ke fungsi suspending yang kita buat pada langkah sebelumnya:

Nilai kembalian dari fungsi launch() adalah objek Job, yang dapat Anda gunakan untuk mengelola coroutine. Misalnya, Anda dapat memanggil metode join() untuk menunggu coroutine selesai. Demikian pula, Anda dapat memanggil metode cancel() untuk membatalkan coroutine.

Menggunakan fungsi launch() adalah seperti membuat thread baru dengan objek Runnable, terutama karena Anda tidak dapat mengembalikan nilai apapun. Jika Anda ingin dapat mengembalikan nilai dari coroutine Anda, Anda harus menggunakan fungsi async() sebagai gantinya.

Fungsi async() mengembalikan sebuah objek Deferred, yang seperti objek Job, memungkinkan Anda untuk mengelola coroutine. Namun, hal ini juga memungkinkan Anda untuk menggunakan fungsi await() untuk menunggu hasil dari coroutine tanpa menghalangi thread saat ini.

Sebagai contoh, perhatikan contoh coroutines berikut yang menggunakan fungsi suspending fetchWebsiteContents() dan mengembalikan nilai panjang dari dua alamat web yang berbeda:

Dengan kode di atas, kedua coroutines akan segera dimulai dan berjalan secara paralel.

Jika Anda sekarang ingin menggunakan nilai lenght, Anda harus memanggil metode await() pada kedua objek Deferred. Namun, karena metode await() merupakan fungsi suspending, Anda harus memastikan bahwa Anda memanggilnya dari coroutine lain.

Kode berikut memperlihatkan bagaimana menghitung jumlah dari dua length menggunakan coroutine baru yang dibuat dengan fungsi launch():

7. Menggunakan Coroutines pada UI Thread

Coroutines menggunakan background threads secara internal, karena itulah coroutines tidak berjalan pda UI thread  aplikasi Android secara default. Akibatnya, jika Anda mencoba memodifikasi konten dari antarmuka aplikasi Anda dari dalam coroutine, Anda akan menemukan kesalahan runtime. Untungnya, menjalankan coroutine di thread UI bisa dibilang sangat mudah: Anda hanya perlu melewati objek UI sebagai argumen dari coroutine builder Anda.

Sebagai contoh, berikut adalah bagaimana Anda dapat menulis ulang coroutine terakhir untuk menampilkan jumlah dalam widget TextView:

Kode di atas mungkin tampak biasa pada awalnya, tapi lihat lagi. Ini tidak hanya mampu menunggu dua background service selesai tanpa menggunakan callback, namun bisa melakukannya di UI thread pada aplikasi tanpa membloknya!

Memiliki kemampuan untuk menunggu di UI thread, tanpa membuat UI Anda terasa lamban atau memicu kesalahan  Application Not Responding, yang sering disebut sebagai ANR, menyederhanakan banyak tugas yang rumit.

Misalnya, dengan fungsi suspending delay(), yang setara dengan metode non-blocking Thread.sleep(), Anda dapat membuat animasi dengan loop. Untuk membantu Anda memulai, berikut adalah contoh coroutine yang akan menambahkan koordinat x dari widget TextView setiap 400 ms, sehingga menciptakan efek marquee-like:

Kesimpulan

Saat mengembangkan aplikasi Android, sangat penting untuk Anda menjalankan operasi yang membutuhkan waktu lama di dalam background thread. Dalam tutorial ini, Anda mempelajari beberapa pendekatan yang dapat Anda ikuti untuk menciptakan dan mengelola thread semacam itu pada Kotlin. Anda juga belajar bagaimana menggunakan fitur coroutines yang masih eksperimental untuk menunggu di dalam thread tanpa menghalanginya.

Untuk mempelajari lebih lanjut tentang coroutines, Anda dapat merujuk ke official documentation. Dan sementara Anda berada di sini, Anda bisa membaca beberapa posting kami tentang Kotlin dan pengembangan aplikasi Android!

Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.