OOZOU
تواصلوا معنا
العودة إلى المدونة

ما يجب معرفته قبل البدء باستخدام Coroutine على Android

باختصار، Coroutine طريقة لكتابة كود غير متزامن (Asynchronous) بأسلوب متزامن (Synchronous) مباشر، دون الحاجة إلى كومة من الـ callbacks.

13 مايو 2020
4 دقائق للقراءة
ما يجب معرفته قبل البدء باستخدام Coroutine على Android

لا بد أن كل مطوّر Android قد سمع عن Coroutine الآن. فخلال السنوات القليلة الماضية، اكتسبت Coroutine شعبية كبيرة في مجتمع Android إلى جانب Kotlin. في هذا المقال سأتحدث عن أساسيات Coroutine التي تمنيت لو عرفتها حين بدأت استكشافها. باختصار، Coroutine طريقة لكتابة كود غير متزامن (Asynchronous) بأسلوب متزامن (Synchronous) مباشر، دون الحاجة إلى كومة من الـ callbacks. لن نضيّع الوقت. إليكم مثالًا على كيفية استخدام Coroutine.

class ArtistViewModel(
    private val getArtistsUseCase: GetArtistsUseCase
) : ViewModel(), CoroutineScope {

    private val job = Job()

    val artistsLiveData: MutableLiveData<List<Artist>> = MutableLiveData()

    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Main

    fun getArtist() {
        launch {
            val artistResponse = withContext(Dispatchers.IO) {
                getArtistsUseCase("Slayer")
            }

            artistsLiveData.value = artistResponse?.result?.map {
                Artist(it.name, it.genreName)
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        job.cancel()
    }
}

في هذا الكود لدينا class من نوع ViewModel. نستخدم Coroutine لجلب قائمة كائنات Artist من الـ API عبر getArtistUseCase. وقد يُعدّ هذا الأسلوب في استخدام Coroutine مع ViewModel قديمًا بعض الشيء، فهناك طريقة أسهل، لكن لنؤجلها قليلًا. قبل المتابعة، سأشرح المصطلحات المهمة التالية.

  • Coroutine context يحدد كيفية تنفيذ الـ Coroutines، مثل تشغيلها على UI Thread أو على IO Thread. يتكوّن Coroutine Context من عناصر مختلفة، أهمها عنصران: الـ Job الخاص بالـ Coroutine والـ Dispatcher الخاص بها- Job من حيث المفهوم شيء قابل للإلغاء، ويمكن تنظيمه في تسلسل هرمي من الآباء والأبناء. وإلغاء الأب يؤدي إلى إلغاء جميع أبنائه.

  • Dispatchers تحدد الـ thread (أو الـ threads) التي ستُنفَّذ عليها الـ coroutine المعنية. وهناك نوعان هما الأكثر استخدامًا: Dispatchers.Main نستخدمه حين نريد تشغيل الـ Coroutine على UI Thread، بينما Dispatchers.IO مخصص للـ Coroutine التي تحجب الـ thread الحالي، مثل استدعاء خدمة API أو الوصول إلى قواعد البيانات أو الملفات.

  • Coroutine Builder يُستخدم لإنشاء Coroutine جديدة. وهناك ثلاثة builders رئيسية.

    • launch؛ ربما يكون launch الأكثر استخدامًا لأنه أسهل طريقة لإنشاء Coroutine. والـ Coroutines التي ينشئها launch لا تحجب الـ thread الجاري.
    • async؛ وهو builder يستطيع إرجاع قيمة من داخل الـ Coroutine.
    • runBlocking؛ هذا الـ builder عكس launch، لأنه يحجب الـ Thread الجاري. وستستخدمونه غالبًا عند كتابة اختبارات الـ Coroutines.
  • CoroutineScope يحدد نطاقًا (scope) للـ coroutines الجديدة. والـ Coroutine builder (مثل launch و async وغيرهما) هو extension على CoroutineScope، ويرث منه CoroutineContext لينقل جميع عناصره وعمليات الإلغاء تلقائيًا.

لنعد إلى مثالنا. سننشئ Coroutine لجلب البيانات من خدمة API، ولنفصّل ذلك خطوة بخطوة.

لإنشاء Coroutine، نحتاج إلى تحديد Coroutine Context للـ Coroutine Builder.

class ArtistViewModel( 
    private val getArtistsUseCase: GetArtistsUseCase
): ViewModel(), <strong>CoroutineScope</strong> {
   private val job = Job() 

   override val coroutineContext: CoroutineContext        
        get() = job + Dispatchers.Main
    ...
    override fun onCleared() {
        super.onCleared()
        job.cancel()
    }
}

نجعل الـ class ArtistViewModel يطبّق CoroutineScope، وهذا يلزمنا أيضًا بعمل override لـ Coroutine Context.

override val coroutineContext: CoroutineContext        
        get() = job + Dispatchers.Main

يعني الجزء أعلاه أن الـ Dispatcher الافتراضي للـ Coroutine في هذا الـ Class هو Dispatchers.Main، وأن job يتيح لنا التحكم في إلغاء الـ Coroutine داخل هذا الـ class عبر استدعاء **job.cancel()**في المثال، نستدعي job.cancel() داخل onCleared() حتى تتوقف الـ Coroutines إذا أُتلف الـ viewModel. لننتقل الآن إلى الجزء الذي تُنشأ فيه الـ Coroutine.

launch {    
    val response = <strong>withContext</strong>(Dispatchers.IO) {       
        getArtistsUseCase("Slayer")            
    } 

    artistsLiveData.value = response?.result
}

بما أننا نحتاج إلى استدعاء خدمة API، فهكذا ننتقل من التنفيذ على الـ Main thread إلى الـ IO thread. نستخدم withContext للتبديل من Dispatcher.Main إلى Dispatcher.IO، وسيُنفَّذ الكود داخل كتلة withContext على الـ IO thread. ويمكن تطبيق المفهوم نفسه على مكونات أخرى غير ViewModel، مثل Presenter أو Activity أو Fragment.

في الواقع، مع ViewModel في مكتبات AndroidX lifecycle v2.1.0، يتوفر viewModelScope الذي يمثل نطاق Coroutine الخاص بالـ ViewModel والمرتبط بدورة حياته. لذلك لم نعد بحاجة إلى استدعاء job.cancel() داخل onClear(). إليكم المثال التالي.

class ArtistViewModel(
    private val getArtistsUseCase: GetArtistsUseCase
) : ViewModel() {
    val artistsLiveData: MutableLiveData<List<Artist>> = MutableLiveData()

    fun getArtist() {
        viewModelScope.launch {
            val artistResponse: ResponseWrapper<ArtistApi>? = withContext(Dispatchers.IO) {
                getArtistsUseCase("Slayer")
            }

            artistsLiveData.value = artistResponse?.result?.map {
                Artist(it.name, it.genreName)
            }
        }
    }
}

يمكنكم أيضًا الاطلاع على الكود في المستودع الخاص بي.

  • بدون viewModelScope: https://github.com/BenBoonya/simple-coroutine-in-android-demo
  • مع viewModelScope: https://github.com/BenBoonya/simple-coroutine-in-android-demo/tree/viewmodel-scope

المصدر

صورة غلاف المقال مأخوذة من العمل الفني لألبوم Fear Inoculum لفرقة Tool.

Related Articles

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

تصميم البرمجيات عملية ممتعة لكنها معقدة، تتطلب الإبداع والتفكير المنطقي ومهارات حل المشكلات.

اقرأوا المزيد
مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

يتطور المشهد الرقمي بسرعة، وعلى الشركات أن تتكيّف لتواكب الطلب المتزايد على السرعة والكفاءة والمعالجة في الوقت الفعلي.

اقرأوا المزيد
مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

يتطور قطاع التجزئة بوتيرة غير مسبوقة بفضل الذكاء الاصطناعي (AI) والواقع المعزّز (AR) وتقنيات التحوّل الرقمي. فلم تعد المتاجر التقليدية مجرد أماكن لبيع المنتجات، بل أصبحت متاجر ذكية وتفاعلية.

اقرأوا المزيد

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

ابدأوا المحادثةhello@oozou.com
OOZOU Logo

بانكوك · سنغافورة · هونغ كونغ

X
Facebook
Instagram
LinkedIn
OOZOU Co., Ltd.
548 One City Centre
Ploenchit Road
Bangkok 10330
Thailand
+66 2544 0000
hello@oozou.com

الخدمات

  • تطوير الويب
  • وكلاء الذكاء الاصطناعي والذكاء الاصطناعي التوليدي
  • تطوير تطبيقات الجوال
  • تحليلات البيانات وهندستها
  • تصميم تجربة المستخدم وواجهته (UX/UI) وتصميم المنتجات
  • التحوّل الرقمي

الشركة

  • من نحن
  • الوظائف
  • المدونة
  • دراسات الحالة
  • عروض حية
  • تعلّمت اليوم
  • تواصل معنا

المزيد

  • القطاعات
  • شبكة الشركاء
© 2026 OOZOU. جميع الحقوق محفوظة.
سياسة الخصوصيةمدونة قواعد السلوكسياسة مكافحة الرشوة والفساد