كيفية استبدال AsyncTask بـ Coroutines من Kotlin

هل مازلت تستخدم AsyncTask في تطبيقات Android؟ ربما لا ينبغي أن تكون كذلك بعد الآن. وإليك كيفية استبدالها بـ Coroutines من Kotlin.

لفترة طويلة جدًا في Android، إذا كنت بحاجة إلى القيام بأي شيء بشكل غير متزامن عند إنشاء تطبيق، فمن المحتمل أنك تستخدم AsyncTask. AsyncTask عبارة عن واجهة برمجة تطبيقات في إطار عمل Android تسهل (عش) تشغيل العمليات في الخلفية وإرجاع القيم عند الانتهاء. وهذا منطقي. على عكس Coroutines في Kotlin، فإن AsyncTask موجود منذ فترة، وهو مدمج فيه.

ومع ذلك، أصبحت فلسفة التصميم وتنفيذ AsyncTask قديمة بعض الشيء على مر السنين. ولهذا السبب، قامت جوجل تم إهمال واجهة AsyncTask API. لا يزال بإمكانك استخدامه إذا أردت، ولكن جوجل لا توصي بذلك. لحسن الحظ، هناك مجموعة كاملة من البدائل لـ AsyncTask، بما في ذلك إحدى ميزات لغة Kotlin - coroutines.

تعد واجهة برمجة تطبيقات coroutines الخاصة بـ 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'
}

قم بمزامنة مشروعك، وستصبح مخططات 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() يعمل على أي مؤشر ترابط تم تشغيله عليه، ولكنه يفعل ذلك بشكل غير متزامن. هذا يعني أنه يمكنك تحديث طرق العرض وما إلى ذلك دون الحاجة إلى القلق بشأن استخدام الموضوع الصحيح.

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() إذا أردت. لذا فإن المثال الأصلي يمكن أن يصبح هكذا.

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
}
}

باستخدام مع السياق

للراحة، توفر 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
}
}

خاتمة

الأمثلة المذكورة أعلاه هي مجرد بعض الاستخدامات الأساسية لكوروتينات Kotlin لتبدأ. لا يتعين عليك قصر الكورتينز على الأنشطة أو حتى أي شيء له دورة حياة مناسبة. يمكنك تشغيلها بشكل أساسي في أي مكان. هناك أيضًا عمليات أكثر تقدمًا، مثل اختيار مؤشر الترابط الذي يجب أن يقوم بتشغيل المنطق غير المتزامن. هذا الدليل مخصص بشكل أساسي لإظهار كيفية استبدال AsyncTask البسيط بكوروتين بسيط.

لمزيد من التفاصيل حول كيفية عمل الكوروتينات، وكيف يمكنك الاستفادة من ميزاتها الأكثر تقدمًا، قم بمراجعة وثائق Kotlin الرسمية.