כיצד להחליף את AsyncTask ב-Cotlin's Coroutines

האם אתה עדיין משתמש ב-AsyncTask באפליקציות האנדרואיד שלך? אתה כנראה לא צריך להיות יותר. הנה איך להחליף אותם ב-Cotlin's Coroutines.

במשך זמן רב מאוד באנדרואיד, אם היית צריך לעשות משהו אסינכרוני בעת יצירת אפליקציה, סביר להניח שהיית משתמש ב-AsyncTask. AsyncTask הוא API במסגרת של אנדרואיד שמקל (יש) להפעיל פעולות ברקע ולהחזיר ערכים בסיום. וזה הגיוני. שלא כמו Coroutines של Kotlin, AsyncTask קיים כבר זמן מה, והוא מובנה ישירות.

עם זאת, גם פילוסופיית העיצוב וגם היישום של AsyncTask הפכו מעט מיושנים במהלך השנים. בגלל זה, לגוגל יש הוציא משימוש את AsyncTask API. אתה עדיין יכול להשתמש בו אם תרצה, אבל גוגל לא ממליצה לעשות זאת. למרבה המזל, יש חבורה שלמה של אלטרנטיבות ל-AsyncTask, כולל תכונה של שפת Kotlin - קורוטינים.

ה-API של Coroutines של Kotlin הוא מסגרת עוצמתית להפליא המאפשרת לך לעשות חבורה שלמה של דברים. המאמר הזה רק הולך לגרד את פני השטח של מה שאפשר. נעבור על היסודות הדרושים למעבר מ-AsyncTask ל-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'
}

סנכרן את הפרויקט שלך, והקורוטינים של Kotlin יהיו זמינים כעת לשימוש.

שימוש בקורוטינים

יישום CoroutineScope

כדי להשתמש ב-coroutines, תצטרך להיות מופע 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() פועל על כל Thread בו הוא הושק, אך עושה זאת באופן אסינכרוני. זה אומר שאתה יכול לעדכן תצוגות וכאלה מבלי שתצטרך לדאוג לגבי השימוש ב-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"
}
}
}

כפי שאתה יכול לראות, השימוש בקורוטינים יכול להיות הרבה יותר פשוט משימוש ב-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() אם אתה רוצה. אז הדוגמה המקורית יכולה להפוך למשהו כזה.

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

מטעמי נוחות, קוטלין מספקת 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
}
}

סיכום

הדוגמאות שלמעלה הן רק כמה שימוש בסיסי בקורוטינות של קוטלין כדי להתחיל. אתה לא צריך להגביל את הקורוטינות לפעילויות או אפילו למשהו עם מחזור חיים תקין. אתה יכול להפעיל אותם בעצם בכל מקום. יש גם פעולות מתקדמות יותר, כמו בחירה באיזה Thread יפעיל את ההיגיון האסינכרוני. מדריך זה נועד בעיקר להראות כיצד להחליף AsyncTask פשוט בקורוטין פשוט.

לפרטים נוספים על אופן הפעולה של קורוטינים וכיצד אתה יכול לעשות שימוש בתכונות המתקדמות יותר שלהם, עיין ב- תיעוד רשמי של קוטלין.