التدفق Flow
بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته
في هذا الدرس سنتعرف على التيار Stream البارد بما يسمى بـ التدفق Flow. والذي يعتبر مشابهاً للـ RxJava.
ماذا ستقرأ
- مقدمة.
- ماهو التدفق Flow.
- كيف نتعامل مع التدفق؟
- أمثلة برمجية.
يعتبر هذا الدرس مرتبط بالدرس السابق القنوات Channels لذلك من الافضل الاطلاع علية اولاً.
مقدمة
سابقاً في البنائين والدوال التأجيلية علمنا أن الدالة التي تبنى بالبناء async تقوم بإرجاع قيمة واحدة مغلفة في عنصر من نوع Deferred. واذا اردنا ارجاع اكثر من قيمة فأننا نقوم بإستخدام التيار الحار Stream المسمى بالقنوات Channels. ولكن اذا اردنا ارجاع اكثر من قيمة بشكل تنافسي Concurrent فأننا سنحتاج الى نوع آخر من التيارات Streams ويأتي هنا النوع البارد المسمى بالتدفق Flow ليحل هذه المشكلة.
ماهو التدفق Flow؟
يعتبر التدفق Flow احدى الاستراتيجيات من التيارات Streams. وهو يمثل طريقة لنقل العناصر بين الكروتينات في شكل تنافسي Concurrent غير متزامن في التوقيت Asynchronous. ويعتبر من التيارات الباردة ومن خلال الدرس السابق نستطيع فهم الفرق بين التيار البارد والحار كالتالي:
يكمن الاختلاف بينهما في أن القناة تعتبر تيار حار, وهذا يعني أنها سوف تقوم بإرسال النتائج لتلبية طلبنا بشكل مستمر سواء كنا منصتين لها أم لا. أما التدفق فيعتبر تيار بارد, وهذا يعني بإنه سوف يقوم بإرسال النتائج لتلبية طلبنا فقط إذا كنا منصتين له. وفي العادة فإن استخدام القنوات يكون مكلفاً نوعاً ما, ويقتصر على الأنواع البدائية.
وهكذا فأن تلقي المعلومات فقط عند الاستماع الى المرسل يكون اقل تكلفة, ولذلك يكون التدفق Flow افضل من القنوات Channel لإرسال وأستقبال البيانات الغير بدائية (كالـ Models لديك).
اذن نستخدم التدفق في حالتين:
- اذا اردنا ان نحصل على تيار من البيانات فقط اذا كنا منصتين له.
- أو اذا اردنا ان نحصل على تيار من البيانات بشكل تنافسي Concurrent غير متزامن في التوقيت Asynchronous.
كيف نتعامل مع التدفق؟
الأساس هو الواجهة المسماة بالـ Flow ونستطيع التعامل وإنشاء التدفقات من خلال العديد من الدوال الاضافية Extension Functions الموجودة في الـ API. مع الانتباه إلى أن بعض من هذه الدوال تأجيلية Suspend Functions وبعضها لا. والدوال التي تلعب دور كبير هي دالة الـ emit التي تقوم وظيفتها ببعث (ارسال) العناصر, والدالة الاخرى هي collect التي تقوم وظيفتها في تجميع (استقبال) العناصر.
ومن الدوال التي تمكننا من إنشاء تدفقات هي الدالة flow و asFlow و flowOf و channelFlow والتي يتم تسميتهم بالبنائين للتدفق Flow Builders. أما لتغيير الـ Context (يقصد هنا الخيط الحاسوبي) نقوم بإستخدام الدوال flowOn أو flowWith والتي وظيفتهم مشابهة لوظيفة الدالة withContext في درس الدوال التأجيلية.
وكذلك توجد الكثير من الدوال المهمة للتعامل والتلاعب بالتدفقات مثل map و filter و zip وما الى ذلك. للإطلاع على جميع الدوال راجع المصادر. وقد لايبدو التعامل مع التدفق آمراً صعباً لمن أستخدم RxJava وميثلاته من تقنيات الـ Reactive Streams.
وبالعادة ستتعامل مع التدفق بشكل مستقبل من خلال العديد من الدوال امثال collect و single و singleOrNull و first و toList و toSet وما الى ذلك. فالعديد من المكاتب قامت بدعم هذه الشئ لتدفق البيانات وماعليك سوى استقبالها. كمكتبة الـ Room الخاصة بقاعدة البيانات في الاندرويد.
أمثلة برمجية
إنشاء تدفق:
// Flow is Type.
// flow is Builder for that type.
fun myFlow(): Flow<Int> = flow {
for (i: Int in 1..3) {
delay(300) // flow { this block can be suspended }
emit(i) // Sending
}
}
- لاحظ النوع هو Flow وقمنا بإستخدام البناء\الدالة flow لصناعته.
- لاحظ اننا نستطيع تأجيل الشفرة بداخل البناء flow (بدلاً من الحجب والتهنيق).
- لاحط أننا لانحتاج للمعرف suspend في الدالة. فالـ Flow يغنينا عن ذلك.
- نقوم بإرسال العناصر الى داخل التدفق بإستخدام الدالة emit.
أستقبال التدفق:
fun main() {
// A Coroutine.
GlobalScope.launch(Dispatchers.Default) {
// Receiving.
myFlow().collect { value: Int ->
println(value)
}
}
// let the program wait.
Thread.sleep(1000)
}
- قمنا بإستقبال التدفق بداخل كروتين.
- نقوم بإستقبال العناصر المرسله من خلال التدفق بإستخدام الدالة collect.
يتميز التدفق في انه مرن جداً, فمن خلال العديد من الدوال والبرمجية الدالية نستطيع التعامل معاه بسهوله ومرونه (راجع المصادر للحصول على كافة الدوال وامثلتها). كذلك فانه مناسب جداً للإشياء التي نحتاج الى استخدام تقنية التنافس Concurent إي تشغيل الشفرة بشكل الـ Asynchronous ومن بعض تلك الاشياء:
- الاتصال بقاعدة البيانات وجلب المعلومات منها, حيث ستكثر استخدامه عندما تتعامل مع مكتبة الـ Room في الاندرويد.
- الاتصال بالسيرفرات من خلال API.
- وماشابه ذلك من أمور.
الى هنا نصل الى نهاية هدا الدرس, ونهاية هذه الدورة. الى اللقاء في مقالات تفصيلية قادمة مستقبلاً ان شاء الله في برمجة الاندرويد مع الكروتينات.
المصادر
- كتاب Learning Concurrency in Kotlin.
- كتاب Elements of Kotlin Coroutines.
- الـ Kotlin Flow Docs.
- الـ Kotlinx.coroutines Flow Docs.
- مقالة Kotlin Flows and Coroutines.
- مقالة Reactive Streams and Kotlin Flows يبين العلاقة بين Flow و Rx ومشتقاته.
محتوى الدورة
مقدمة | |
---|---|
1 | مقدمة |
الروتينات التعاونية | |
1 | نظرة عامة على الـ Coroutines |
2 | نظرة خاصة على الـ Coroutines في لغة الكوتلن |
3 | إنشاء الكروتين Coroutine |
مكونات الروتينات التعاونية | |
1 | النطاقات الـ Scopes |
2 | البنائين الـ Builders |
3 | الموزعين الـ Dispatchers |
الدوال التأجيلية | |
1 | الدوال التأجيلية Suspended Functions |
التيارات Streams | |
1 | القنوات Channels |
2 | التدفق Flow الدرس الحالي |
الكلمات الدليلية
عن الدرس
1 إعجاب |
1 متابع |
0 مشاركة |
1750 مشاهدات |
منذ 4 سنوات |
التعليقات (0)
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !