catch وonCompletion: معالجة الأخطاء في Flow
التقط استثناءات المنبع واستجب لأحداث اكتمال التدفق.
catch وonCompletion: معالجة الأخطاء في Flow درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
أساسيات استثناءات Flow
تنهي الاستثناءات التدفق. ومن دون معالجتها، ينتشر الاستثناء إلى جامع التدفق وينتهي التدفق.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw RuntimeException("stream error")
emit(2)
}.collect { println(it) }
} catch (e: Exception) {
println("Caught: ${e.message}")
}
}عامل catch
يعالج catch الاستثناءات الصادرة من المصدر ويمكنه إصدار قيم بديلة أو إعادة طرح الاستثناء. لكنه لا يلتقط الاستثناءات التي يطرحها الجامع نفسه.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
emit(1)
throw RuntimeException("oops")
}.catch { e ->
println("Caught: ${e.message}")
emit(-1) // fallback value
}.collect { println(it) } // 1, then -1
}يعالج catch الاستثناءات من المصدر فقط
يعترض catch الاستثناءات الصادرة من منشئ التدفق والعوامل السابقة فقط — وليس من lambda الخاص بـ collect.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flowOf(1, 2, 3)
.catch { e -> println("upstream: ${e.message}") }
.collect {
if (it == 2) throw RuntimeException("collector error") // not caught by catch
println(it)
}
} catch (e: Exception) {
println("Collector exception: ${e.message}")
}
}إعادة طرح الاستثناء في catch
يمكنك فحص الاستثناء وإعادة طرح الاستثناءات التي لا تستطيع معالجتها انتقائيًا.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw IllegalStateException("state error")
}.catch { e ->
if (e is RuntimeException) { emit(-1); return@catch }
throw e // rethrow unknown exceptions
}.collect { println(it) }
} catch (e: Exception) {
println("Rethrown: ${e.message}")
}
}عامل onCompletion
يُنفَّذ onCompletion عند اكتمال التدفق — سواءً بشكل طبيعي أو مع استثناء. وتكون معلَمة cause غير فارغة عند الفشل.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowOf(1, 2, 3)
.onCompletion { cause ->
if (cause == null) println("Completed normally")
else println("Failed: ${cause.message}")
}
.collect { println(it) }
}onCompletion عند حدوث خطأ
يُنفَّذ onCompletion حتى عند حدوث استثناء من المصدر. ويتلقى الاستثناء في cause، لكنه لا يخفيه — إذ يستمر الاستثناء في الانتشار.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw RuntimeException("error")
}.onCompletion { cause ->
println("onCompletion cause=${cause?.message}")
}.collect { println(it) }
} catch (e: Exception) {
println("outer catch: ${e.message}")
}
}الجمع بين catch وonCompletion
استخدم catch للتعافي وإصدار قيم بديلة، ثم استخدم onCompletion للتسجيل أو تحرير الموارد بغض النظر عن النتيجة.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
emit("ok")
throw RuntimeException("network error")
}.catch { e ->
emit("fallback") // recover
}.onCompletion {
println("Stream done — release resources")
}.collect { println(it) }
}عامل retry
يعيد retry(n) { ... } الاشتراك في التدفق المصدر عند حدوث استثناء، بحد أقصى n مرات.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
var attempt = 0
fun unstableFlow() = flow {
attempt++
if (attempt < 3) throw RuntimeException("attempt $attempt failed")
emit("success on attempt $attempt")
}
fun main() = runBlocking {
unstableFlow()
.retry(3) { e -> println("retrying: ${e.message}"); true }
.collect { println(it) }
}استخدام retryWhen لمنطق مخصص
يوفر retryWhen الاستثناء وعدد المحاولات، مما يتيح لك إضافة التأخير التدريجي أو تحديد الاستثناءات التي تؤدي إلى إعادة المحاولة.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
var n = 0
flow {
if (n++ < 2) throw IOException("IO error")
emit("done")
}.retryWhen { cause, attempt ->
cause is IOException && attempt < 3
}.collect { println(it) }
}عامل onStart
يُنفَّذ onStart قبل الإصدار الأول — وهو مفيد لعرض حالات التحميل أو تهيئة الموارد قبل وصول البيانات.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowOf("data")
.onStart { emit("Loading...") }
.onCompletion { emit("Done") }
.collect { println(it) }
}معالجة الأخطاء في استدعاءات API الحقيقية
لفّ تدفقات المستودع باستخدام catch لتحويل الاستثناءات إلى أخطاء على مستوى المجال، واستخدم onCompletion لإخفاء مؤشرات التحميل.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class State { object Loading : State(); data class Data(val v: String) : State(); data class Error(val msg: String) : State() }
fun apiFlow(): Flow<String> = flow { delay(50); emit("response") }
fun uiFlow(): Flow<State> = apiFlow()
.map { State.Data(it) as State }
.onStart { emit(State.Loading) }
.catch { e -> emit(State.Error(e.message ?: "unknown")) }
fun main() = runBlocking { uiFlow().collect { println(it) } }تحقق سريع
ما القيد الأساسي لمعامل catch؟
مراجعة
يتعامل catch مع استثناءات المنبع ويمكنه إصدار قيم بديلة. يُنفَّذ onCompletion دائمًا، سواء اكتمل التنفيذ طبيعيًا أو حدث خطأ، لإجراء التنظيف أو التسجيل. ادمجهما مع retry/retryWhen لإنشاء مسارات تدفق مرنة وقادرة على تحمل الأخطاء.
تعلم Kotlin مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 51
- الدروس
- 203
الأسئلة الشائعة
هل درس «catch وonCompletion: معالجة الأخطاء في Flow» مجاني؟
نعم — نص درس «catch وonCompletion: معالجة الأخطاء في Flow» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ماذا ستتعلم في «catch وonCompletion: معالجة الأخطاء في Flow»؟
التقط استثناءات المنبع واستجب لأحداث اكتمال التدفق. تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟
لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «catch وonCompletion: معالجة الأخطاء في Flow»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟
نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- معاملات Flow: map وfilter وtransform وtake
- catch وonCompletion: معالجة الأخطاء في Flow
- combine وzip: دمج تدفقات Flow متعددة
- flowOn وbuffer: السياق والضغط العكسي