วิธีแทนที่ AsyncTask ด้วย Coroutines ของ Kotlin

คุณยังคงใช้ AsyncTask ในแอพ Android ของคุณหรือไม่? คุณคงไม่ควรจะเป็นอีกต่อไป ต่อไปนี้เป็นวิธีแทนที่ด้วย Coroutines ของ Kotlin

เป็นเวลานานมากใน Android หากคุณต้องการทำอะไรแบบอะซิงโครนัสเมื่อสร้างแอป คุณอาจใช้ AsyncTask AsyncTask เป็น API ในเฟรมเวิร์กของ Android ที่ทำให้การรันการดำเนินการในเบื้องหลังเป็นเรื่องง่าย (ish) และส่งคืนค่าเมื่อดำเนินการเสร็จแล้ว และนั่นก็สมเหตุสมผล AsyncTask ต่างจาก Coroutines ของ Kotlin ตรงที่มีมาระยะหนึ่งแล้วและมีการติดตั้งในตัว

อย่างไรก็ตาม ทั้งปรัชญาการออกแบบและการใช้งาน AsyncTask ค่อนข้างล้าสมัยในช่วงหลายปีที่ผ่านมา ด้วยเหตุนี้ Google จึงได้ เลิกใช้ AsyncTask API แล้ว. คุณยังคงสามารถใช้งานได้หากต้องการ แต่ Google ไม่แนะนำให้ทำเช่นนั้น โชคดีที่มีทางเลือกมากมายสำหรับ AsyncTask รวมถึงฟีเจอร์ของภาษา Kotlin — coroutines

Coroutines API ของ Kotlin เป็นเฟรมเวิร์กที่ทรงพลังอย่างเหลือเชื่อ ซึ่งช่วยให้คุณทำสิ่งต่างๆ ได้มากมาย บทความนี้เป็นเพียงการเริ่มต้นของสิ่งที่เป็นไปได้เท่านั้น เราจะพูดถึงพื้นฐานที่จำเป็นในการย้ายจาก AsyncTask ไปยัง Coroutines

การเพิ่มการสนับสนุน Coroutines

ก่อนที่คุณจะเริ่มใช้ coroutines ได้ คุณต้องเพิ่มมันลงในโปรเจ็กต์ของคุณเสียก่อน

การเพิ่มการสนับสนุน Kotlin

หากคุณได้ติดตั้ง Kotlin ไว้แล้ว ให้ข้ามไปยังส่วนถัดไป มิฉะนั้น คุณจะต้องเพิ่มการรองรับ Kotlin ให้กับโปรเจ็กต์ของคุณ ดูบทช่วยสอนของฉันเกี่ยวกับการเพิ่ม Kotlin ให้กับโปรเจ็กต์ที่มีอยู่เพื่อดูรายละเอียดเพิ่มเติม

การเพิ่มไลบรารี Coroutine

ในระดับโมดูลของคุณ build.gradleรวมถึงการอ้างอิงต่อไปนี้

dependencies {
...
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-core: 1.5.0'
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-android: 1.5.0'
}

ซิงค์โปรเจ็กต์ของคุณ จากนั้น Coroutines ของ Kotlin ก็พร้อมใช้งานแล้ว

การใช้โครูทีน

การใช้ CoroutineScope

หากต้องการใช้ Coroutine คุณจะต้องมีอินสแตนซ์ CoroutineScope ที่พร้อมใช้งาน วิธีง่ายๆ ในการทำเช่นนี้คือการนำไปใช้ในคลาสที่มีของคุณ

ตัวอย่างเช่น หากต้องการใช้ CoroutineScope ในกิจกรรม:

classSomeActivity : AppCompatActivity, CoroutineScope by MainScope() {
...

override fun onDestroy(){
super.onDestroy()

cancel()
}
}

สิ่งนี้จะทำให้ SomeActivity ใช้อินเทอร์เฟซ CoroutineScope โดยใช้คลาส MainScope MainScope จะจัดการตรรกะการใช้งานทั้งหมดสำหรับ CoroutineScope ในขณะที่ให้คุณใช้เมธอด CoroutineScope ได้ กำลังโทร cancel() ใน onDestroy() ตรวจสอบให้แน่ใจว่าไม่มีตรรกะอะซิงโครนัสทำงานต่อไปหลังจากออกจากกิจกรรมแล้ว

แทนที่ AsyncTask ด้วย Coroutines

สมมติว่าคุณมี AsyncTask อยู่ในกิจกรรมที่ดำเนินการระยะยาวในพื้นหลังและส่งคืนสตริงในที่สุด บางอย่างเช่นต่อไปนี้

private inner classSomeTask : AsyncTask() {
override fun doInBackground(vararg params: Void): String {
try {
//Pretend this is an actual operation that takes 10 seconds and not just sleeping.
Thread.sleep(10000);
} catch (e: InterruptedException) {}

return"SomeString";
}

override fun onPostExecute(result: String) {
val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

การแทนที่สิ่งนี้ด้วยโครูทีนนั้นเป็นเรื่องง่าย เพียงแค่ใช้ async() วิธี. คอตลิน async() ทำงานบนเธรดใดก็ตามที่เปิดใช้งาน แต่ทำงานแบบอะซิงโครนัส ซึ่งหมายความว่าคุณสามารถอัปเดต Views ได้โดยไม่ต้องกังวลกับการใช้ Thread ที่ถูกต้อง

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...

private fun doOperation(){
async {
//Inside coroutine scopes (like inside async here), delay is used instead of Thread.sleep.
delay(10000)

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = "SomeString"
}
}
}

อย่างที่คุณเห็น การใช้ coroutines นั้นง่ายกว่าการใช้ AsyncTask มาก คุณไม่จำเป็นต้องเพียงแค่โทร async() และปล่อยให้มันเป็นไปตามของมัน คุณสามารถเก็บการอ้างอิงไว้และรอให้เสร็จสิ้นได้

val asyncJob = async {
//Some operation
}
//Pause here until the async block is finished.
asyncJob.await()

//This won't run until asyncJob finishes, but other operations started before the job, or started from another method, can still run.
doSomethingElse()

ส่งคืนค่าด้วย async

คุณสามารถคืนค่าจาก async() ถ้าคุณต้องการ. ตัวอย่างเดิมอาจเป็นแบบนี้

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...
private fun doOperation(){
val asyncJob = async {
//Inside coroutine scopes (like inside async here), delay is used instead of Thread.sleep.
delay(10000)

//Whatever the type is of the last line is what async() eventually returns.
"SomeString"
}

val result = asyncJob.await()

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

การใช้ withContext

เพื่อความสะดวก Kotlin จัดให้ withContext(). สิ่งนี้จะอินไลน์ทั้งหมด await() สิ่งและเพียงแค่ส่งกลับค่าให้กับคุณ

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...
private fun doOperation(){
//Run asynchronously on the main Thread.
val result = withContext(Dispatchers.Main) {
delay(10000)

"SomeResult"
}

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

บทสรุป

ตัวอย่างข้างต้นเป็นเพียงการใช้งานเบื้องต้นของ Coroutines ของ Kotlin เพื่อช่วยคุณในการเริ่มต้น คุณไม่จำเป็นต้องจำกัดโครูทีนไว้ที่กิจกรรมหรือแม้แต่สิ่งใดก็ตามที่มีวงจรชีวิตที่เหมาะสม คุณสามารถเรียกใช้งานได้ทุกที่ นอกจากนี้ยังมีการดำเนินการขั้นสูงเพิ่มเติม เช่น การเลือกเธรดใดที่ควรรันตรรกะอะซิงโครนัส คู่มือนี้มีไว้เพื่อแสดงวิธีแทนที่ AsyncTask แบบธรรมดาด้วย Coroutine แบบธรรมดาเป็นหลัก

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการทำงานของ Coroutines และวิธีที่คุณสามารถใช้คุณสมบัติขั้นสูงเพิ่มเติมได้ โปรดดูที่ เอกสาร Kotlin อย่างเป็นทางการ.