---
title: "ما يجب معرفته قبل البدء باستخدام Coroutine على Android"
description: "باختصار، Coroutine طريقة لكتابة كود غير متزامن (Asynchronous) بأسلوب متزامن (Synchronous) مباشر، دون الحاجة إلى كومة من الـ callbacks."
canonical: https://oozou.com/ar/blog/things-you-should-know-before-getting-started-with-coroutine-on-android-32
locale: ar
date: 2020-05-13
author: "OOZOU Team"
---

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

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

Published: 2020-05-13 · Author: OOZOU Team (Engineering) · 4 min read

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

```kotlin
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](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html) و [async](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html) وغيرهما) هو extension على **CoroutineScope**، ويرث منه **CoroutineContext** لينقل جميع عناصره وعمليات الإلغاء تلقائيًا.

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

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

```kotlin
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**.

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

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

```kotlin
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](https://developer.android.com/jetpack/androidx/releases/lifecycle)، يتوفر **viewModelScope** الذي يمثل نطاق Coroutine الخاص بالـ ViewModel والمرتبط بدورة حياته. لذلك لم نعد بحاجة إلى استدعاء **job.cancel()** داخل **onClear()**. إليكم المثال التالي.

```kotlin
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](https://github.com/BenBoonya/simple-coroutine-in-android-demo)
- مع **viewModelScope:** [https://github.com/BenBoonya/simple-coroutine-in-android-demo/tree/viewmodel-scope](https://github.com/BenBoonya/simple-coroutine-in-android-demo/tree/viewmodel-scope)

# المصدر

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

---

Contact OOZOU: hello@oozou.com · +66 2544 0000 · https://oozou.com/ar/contact

More for AI agents: https://oozou.com/llms.txt · every page has a markdown twin at its URL plus ".md"
