مقدمة عن Flow: ما هو ولماذا تحتاجه؟
Flow هي مكتبة للتعامل مع تدفقات البيانات التفاعلية (reactive streams) في لغة البرمجة Kotlin. وهي جزء من نظام Kotlin Coroutines البيئي، وتوفر طريقة قوية وآمنة من حيث الأنواع (type-safe) وغير متزامنة (asynchronous) لمعالجة تسلسلات البيانات التي يتم توليدها بمرور الوقت.
على عكس المجموعات العادية (List, Set) التي تخزن جميع العناصر في الذاكرة دفعة واحدة، فإن Flow يمثل تيارًا باردًا (cold stream). وهذا يعني أن البيانات تبدأ في التوليد فقط عندما يظهر مشترك (collector). Flow مثالي من أجل:
- معالجة البيانات غير المتزامنة: جلب البيانات من الشبكة أو قاعدة البيانات أو نظام الملفات دون حظر الخيط الرئيسي.
- معالجة الأحداث: النقرات، حركات الماوس، تحديثات واجهة المستخدم.
- البرمجة التفاعلية: إنشاء سلاسل من تحويلات البيانات (map, filter, flatMap) مع معالجة تلقائية للأخطاء والإلغاء.
- التكامل مع الكوروتينات: Flow متوافق تمامًا مع Kotlin Coroutines، مما يسمح بدمجه بسهولة مع العمليات غير المتزامنة الأخرى.
لماذا نستخدم Flow بدلاً من الطرق القديمة (مثل RxJava أو callback's)؟
- البساطة والإيجاز: واجهة برمجة التطبيقات (API) الخاصة بـ Flow بسيطة وبديهية لمطوري Kotlin.
- الأمان: أمان على مستوى الأنواع (type-safety) في مرحلة الترجمة.
- التكامل مع الكوروتينات: يستخدم جميع مزايا التزامن المنظم (structured concurrency).
- الأداء: خفيف الوزن وفعال، ولا ينشئ كائنات غير ضرورية.
تثبيت Flow
Flow هو جزء من مكتبة kotlinx.coroutines. لاستخدامه، تحتاج إلى إضافة التبعية (dependency) إلى ملف build.gradle.kts (لـ Gradle) أو pom.xml (لـ Maven).
Gradle (Kotlin DSL)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
// لاستخدام Flow في Android (مع دورة حياة التطبيق)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
}
Gradle (Groovy)
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1'
}
Maven
org.jetbrains.kotlinx
kotlinx-coroutines-core
1.8.1
هام: تأكد من توافق إصدار Kotlin مع إصدار kotlinx-coroutines. يمكنك العثور على أحدث إصدار على GitHub.
بداية سريعة: أول Flow لك
لنقم بإنشاء Flow بسيط يصدر ثلاثة أرقام مع تأخير، ثم نشترك فيه.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun simpleFlow(): Flow<Int> = flow {
println("تم بدء Flow")
for (i in 1..3) {
delay(100) // محاكاة عمل غير متزامن
emit(i) // إصدار القيمة
}
}
fun main() = runBlocking {
println("الخيط الرئيسي: ${Thread.currentThread().name}")
// الاشتراك في Flow (جمع البيانات)
simpleFlow().collect { value ->
println("تم الاستلام: $value")
}
println("تم إنهاء Flow")
}
المخرجات:
الخيط الرئيسي: main
تم بدء Flow
تم الاستلام: 1
تم الاستلام: 2
تم الاستلام: 3
تم إنهاء Flow
الشرح:
flow { ... }— ينشئ تيارًا باردًا (cold stream).emit()— دالة تصدر (تبعث) قيمة جديدة إلى المشتركين.collect()— دالة تجمع (تستهلك) القيم الصادرة من Flow. وهي مشغل نهائي (terminal operator).- يبدأ Flow في العمل فقط عند استدعاء
collect().