توفّر الكوروتينات في Kotlin واجهة برمجة تطبيقات تتيح لك كتابة رمز غير متزامن. باستخدام الكوروتينات في Kotlin، يمكنك تحديد CoroutineScope، ما يساعدك في إدارة وقت تشغيل الكوروتينات. يتم تشغيل كل عملية غير متزامنة
ضمن نطاق معين.
توفّر المكوّنات المتوافقة مع مراحل النشاط دعمًا من الدرجة الأولى لبرامج الكوروتين للنطاقات المنطقية في تطبيقك. يوضّح هذا المستند كيفية استخدام برامج الكوروتين بفعالية مع المكوّنات المتوافقة مع مراحل النشاط.
إضافة التبعيات
يتم تضمين نطاقات الكوروتين المضمّنة الموضّحة في هذا الموضوع في واجهة برمجة التطبيقات Lifecycle. احرص على إضافة التبعيات المناسبة عند استخدام هذه النطاقات.
- بالنسبة إلى أدوات 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. تكون الكوروتين مفيدة هنا عندما يكون لديك عمل يجب إنجازه
فقط إذا كان 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 للتعامل مع نطاق التركيب
بشكل تعريفي.
تنشئ الدالة 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
إلى عنصر Compose State وتدير تلقائيًا اشتراك
مراحل النشاط نيابةً عنك. يبدأ جمع البيانات تلقائيًا عندما تكون مرحلة النشاط
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()
// ...
}
حساب القيم بشكل غير متزامن باستخدام Flows
عندما تحتاج إلى حساب القيم بشكل غير متزامن، استخدِم 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 لتحويل القيم المجمَّعة إلى Compose
State، لكي يتم تعديل واجهة المستخدم بشكل تفاعلي كلما تغيّرت البيانات.
لمزيد من المعلومات حول الحالة، يُرجى الاطّلاع على الحالة وJetpack Compose.
مراجع إضافية
محتوى المشاهدات
نماذج
التطبيقات المقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما يكون JavaScript غير مفعَّل
- التعامل مع مراحل النشاط باستخدام المكوّنات التي تراعي مراحل النشاط
- تحميل البيانات المقسّمة على صفحات وعرضها