البرمجة التفاعلية في Kotlin: قوة kotlinx.coroutines و Flow
\n\nالبرمجة التفاعلية هي نموذج يركز على المعالجة غير المتزامنة لتدفقات البيانات ونشر التغييرات. في نظام Kotlin البيئي، الأداة الرئيسية لتنفيذ الأنماط التفاعلية هي مكتبة kotlinx.coroutines، وبشكل أكثر تحديدًا مكونها Flow. على عكس RxJava، فإن Flow مدمج بشكل وثيق مع coroutines، مما يجعل الكود أكثر إيجازًا وأمانًا.
المفاهيم الأساسية لـ Flow
\n\nFlow هو تدفق بيانات غير متزامن بارد يصدر القيم بشكل تسلسلي. وهو يدعم:
\n- \n
- التدفقات الباردة — يبدأ إنشاء البيانات فقط عند وجود مشترك (عامل تشغيل طرفي). \n
- سياق التنفيذ — يمكن للتدفق التبديل بين موزعي coroutines مختلفين. \n
- الإلغاء عبر coroutines — إلغاء coroutine الأصلي ينهي Flow تلقائيًا. \n
التثبيت والإعداد
\nلاستخدام Flow، أضف التبعية في ملف build.gradle.kts:
dependencies {\n implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")\n}\n\nإنشاء واستهلاك Flow
\nلننشئ تدفقًا بسيطًا للأرقام مع تأخير:
\nimport kotlinx.coroutines.*\nimport kotlinx.coroutines.flow.*\n\nfun simpleFlow(): Flow<Int> = flow {\n for (i in 1..5) {\n delay(100) // محاكاة عمل غير متزامن\n emit(i) // إصدار القيمة\n }\n}\n\nfun main() = runBlocking {\n simpleFlow().collect { value ->\n println("تم الاستلام: $value")\n }\n}\nفي هذا المثال، يقوم flow { ... } بإنشاء تدفق بارد، و collect هو عامل تشغيل طرفي يبدأ التنفيذ.
تحويل البيانات باستخدام عوامل التشغيل
\nيوفر Flow مجموعة غنية من عوامل التشغيل المشابهة لـ RxJava:
\n- \n
map— يحول كل قيمة. \n filter— يقوم بتصفية القيم بناءً على شرط. \n flatMapConcat— يدمج التدفقات بشكل تسلسلي. \n catch— يعالج الاستثناءات داخل التدفق. \n
مثال مع عوامل التشغيل:
\nfun transformFlow(): Flow<String> = flow {\n emit("Kotlin")\n emit("Java")\n emit("Python")\n}.map { it.lowercase() }\n .filter { it.startsWith("k") }\n\nfun main() = runBlocking {\n transformFlow().collect { println(it) }\n // الإخراج: kotlin\n}\n\nمعالجة الأخطاء والإكمال
\nيسمح Flow بمعالجة الاستثناءات بأناقة باستخدام catch وتنفيذ إجراءات الإنهاء عبر onCompletion:
fun errorProneFlow(): Flow<Int> = flow {\n emit(1)\n emit(2)\n throw RuntimeException("خطأ!")\n emit(3) // لن يتم تنفيذه\n}\n\nfun main() = runBlocking {\n errorProneFlow()\n .catch { e -> println("تم التقاط الخطأ: ${e.message}") }\n .onCompletion { println("تم إنهاء التدفق") }\n .collect { println(it) }\n}\n// الإخراج: 1, 2, تم التقاط الخطأ: خطأ!, تم إنهاء التدفق\n\nالتدفقات الساخنة: StateFlow و SharedFlow
\nعلى عكس Flow البارد، فإن StateFlow و SharedFlow هما تدفقات ساخنة تخزن الحالة ويمكن أن يكون لهما عدة مشتركين.
\n\nStateFlow
\nيُستخدم لتخزين ومراقبة الحالة (على سبيل المثال، في ViewModel):
\nclass CounterViewModel {\n private val _counter = MutableStateFlow(0)\n val counter: StateFlow<Int> = _counter.asStateFlow()\n\n fun increment() {\n _counter.value++\n }\n}\n\n// في Activity أو Fragment\nlifecycleScope.launch {\n viewModel.counter.collect { value ->\n textView.text = "العداد: $value"\n }\n}\n\nSharedFlow
\nمناسب لـ