توفّر الكوروتينات في Kotlin واجهة برمجة تطبيقات تتيح لك كتابة رموز برمجية غير متزامنة. باستخدام الكوروتينات في Kotlin، يمكنك تحديد CoroutineScope، ما يساعدك في إدارة الوقت الذي يجب أن يتم فيه تنفيذ الكوروتينات. يتم تنفيذ كل عملية غير متزامنة ضمن نطاق معيّن.
توفّر المكوّنات المتوافقة مع مراحل النشاط إمكانية استخدام سلسة لبرامج coroutines في النطاقات المنطقية داخل تطبيقك. يوضّح هذا المستند كيفية استخدام برامج coroutines بفعالية مع المكوّنات المتوافقة مع مراحل النشاط.
إضافة التبعيات
نطاقات الروتين الفرعي المضمّنة الموضّحة في هذا الموضوع مضمّنة في واجهة برمجة التطبيقات Lifecycle API. احرص على إضافة التبعيات المناسبة عند استخدام هذه النطاقات.
- بالنسبة إلى أدوات ViewModel المساعدة في Compose، استخدِم
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"). - بالنسبة إلى أدوات Lifecycle المساعدة في Compose، استخدِم
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version").
نطاقات الروتين الفرعي التي تراعي مراحل النشاط
توفّر مكتبتا Compose وLifecycle النطاقات المضمّنة التالية التي يمكنك استخدامها في تطبيقك.
ViewModelScope
يتم تحديد ViewModelScope لكل ViewModel في تطبيقك، ويتم تلقائيًا إلغاء أي روتين فرعي يتم تشغيله في هذا النطاق إذا تم محو ViewModel. تكون إجراءات coroutine مفيدة هنا عندما يكون لديك عمل يجب تنفيذه فقط إذا كانت السمة ViewModel نشطة. على سبيل المثال، إذا كنت تحسب بعض البيانات لتصميم معيّن، يجب أن تحدّد نطاق العمل على ViewModel، حتى إذا تمت إزالة ViewModel، يتم إلغاء العمل تلقائيًا لتجنُّب استهلاك الموارد.
يمكنك الوصول إلى CoroutineScope الخاص بـ ViewModel من خلال السمة viewModelScope الخاصة بـ ViewModel، كما هو موضّح في المثال التالي:
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
في حالات الاستخدام الأكثر تقدّمًا، يمكنك تمرير CoroutineScope مخصّص مباشرةً إلى الدالة الإنشائية الخاصة بـ ViewModel لاستبدال viewModelScope التلقائي. يوفّر هذا النهج مزيدًا من التحكّم والمرونة، خاصةً في ما يلي:
الاختبار: يتيح لك إدخال
TestScope، ما يسهّل التحكّم في الوقت والتحقّق من سلوك الروتين الفرعي في اختبارات الوحدات.الإعداد المخصّص: يمكنك ضبط النطاق باستخدام
CoroutineDispatcherمعيّن (مثلDispatchers.Defaultلإجراء عمليات حسابية معقّدة) أوCoroutineExceptionHandlerمخصّص قبل أن تبدأ ViewModel عملها.
نطاقات مرتبطة بالمقطوعة الموسيقية
يجب أن تكون الآثار الجانبية، مثل الرسوم المتحركة أو طلبات الشبكة أو المؤقتات، محصورة في نطاق عمر العنصر القابل للإنشاء. بهذه الطريقة، عندما يغادر عنصر قابل للإنشاء الشاشة (يخرج من التركيب)، يتم تلقائيًا إلغاء أي كوروتينات قيد التشغيل لمنع تسرُّب الذاكرة.
توفّر Compose واجهة برمجة التطبيقات LaunchedEffect للتعامل مع نطاق Composition بشكل تعريفي.
تنشئ LaunchedEffect CoroutineScope تتيح لك تنفيذ دوال تعليق. يرتبط النطاق بدورة حياة المقطوعة الموسيقية للعنصر القابل للإنشاء، وليس بدورة حياة النشاط المضيف.
- الإدخال: تبدأ الروتين الفرعي عندما يدخل العنصر القابل للإنشاء في التركيب.
- الخروج: يتم إلغاء الكوروتين عندما يغادر العنصر القابل للإنشاء التركيب.
- إعادة التشغيل: إذا تغيّر أي مفتاح تم تمريره إلى
LaunchedEffect، يتم إلغاء الكوروتين الحالي ويتم تشغيل كوروتين جديد.
يوضّح المثال التالي كيفية استخدام LaunchedEffect لإنشاء
صورة متحرّكة نابضة. يتم ربط الروتين الفرعي بوجود العنصر القابل للإنشاء في التركيب ويتفاعل مع تغييرات الإعدادات:
// Allow the pulse rate to be configured, so it can be sped up if the user is running // out of time var pulseRateMs by remember { mutableLongStateOf(3000L) } val alpha = remember { Animatable(1f) } LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes while (isActive) { delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user alpha.animateTo(0f) alpha.animateTo(1f) } }
لمزيد من المعلومات حول LaunchedEffect، يُرجى الاطّلاع على الآثار الجانبية في Compose.
جمع بيانات معدّل التدفق مع مراعاة دورة الحياة
لجمع التدفقات بأمان في Jetpack Compose، استخدِم واجهة برمجة التطبيقات
collectAsStateWithLifecycle. تحوّل هذه الدالة المنفردة Flow إلى عنصر State في Compose وتدير تلقائيًا اشتراك دورة الحياة نيابةً عنك. يبدأ جمع البيانات تلقائيًا عندما تكون حالة النشاط STARTED ويتوقف عندما تكون حالة النشاط STOPPED. لتجاوز هذا السلوك التلقائي، مرِّر المَعلمة minActiveState مع طريقة دورة الحياة التي تريدها، مثل Lifecycle.State.RESUMED.
يوضّح المثال التالي كيفية جمع StateFlow الخاص بـ ViewModel في دالة قابلة للإنشاء:
@Composable private fun ConversationScreen( conversationViewModel: ConversationViewModel = viewModel() ) { val messages by conversationViewModel.messages.collectAsStateWithLifecycle() ConversationScreen( messages = messages, onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) } ) } @Composable private fun ConversationScreen( messages: List<Message>, onSendMessage: (Message) -> Unit ) { MessagesList(messages, onSendMessage) /* ... */ }
الجمع المتوازي لعدة مسارات
في Compose، يمكنك جمع عدة تدفقات بشكل متوازٍ من خلال تعريف عدة متغيرات حالة. بما أنّ collectAsStateWithLifecycle يدير نطاقه الأساسي الخاص، يتم تلقائيًا التعامل مع عملية الجمع المتوازية:
@Composable
fun DashboardScreen(viewModel: DashboardViewModel = viewModel()) {
// Both flows are collected safely in parallel and will emit updates when either changes, the composables will recompose
val userData by viewModel.userFlow.collectAsStateWithLifecycle()
val feedData by viewModel.feedFlow.collectAsStateWithLifecycle()
// ...
}
حساب القيم بشكل غير متزامن باستخدام "التدفّقات"
عندما تحتاج إلى حساب القيم بشكل غير متزامن، استخدِم StateFlow مع عامل التشغيل stateIn.
يستخدم المقتطف التالي Flow عادية تم تحويلها إلى StateFlow. تحافظ المَعلمة
WhileSubscribed(5000) على نشاط الاشتراك لمدة خمس ثوانٍ
بعد اختفاء واجهة المستخدم للتعامل مع تغييرات الإعدادات.
val uiState: StateFlow<Result> = flow {
emit(repository.fetchData())
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = Result.Loading
)
استخدِم collectAsStateWithLifecycle لتحويل القيم التي تم جمعها إلى State في Compose، حتى يتمكّن تصميم واجهة المستخدم من التعديل بشكل تفاعلي كلما تغيّرت البيانات.
لمزيد من المعلومات حول الحالة، يُرجى الاطّلاع على الحالة وJetpack Compose.
مراجع إضافية
مشاهدة المحتوى
نماذج
اقتراحات مخصصة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة.
- التعامل مع مراحل النشاط باستخدام المكوّنات التي تراعي مراحل النشاط
- تحميل البيانات المقسّمة إلى صفحات وعرضها