StateFlow
وSharedFlow
هما واجهات برمجة تطبيقات Flow
التي تمكّن التدفقات من إصدار تحديثات الحالة على النحو الأمثل وإطلاق قيم متعددة
المستهلكين.
StateFlow
StateFlow
هو تدفق يمكن ملاحظته من قِبل صاحب الحالة ينبعث من الحالة الحالية والجديدة
تحديثات للمجمعين. ويمكن أيضًا قراءة قيمة الحالة الحالية من خلال
value
الموقع. لتعديل الحالة وإرسالها إلى التدفق، عيِّن قيمة جديدة إلى
السمة value
MutableStateFlow
.
في Android، يُعد StateFlow
مناسبًا جدًا للصفوف التي تحتاج إلى الحفاظ على
حالة قابلة للتغيير.
باتباع الأمثلة من تدفقات Kotlin، يتم إنشاء StateFlow
أن يتعرض من LatestNewsViewModel
حتى يتمكن View
الاستماع إلى تحديثات حالة واجهة المستخدم وإبقاء حالة الشاشة قائمة
تغييرات التهيئة.
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
// Backing property to avoid state updates from other classes
private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
// The UI collects from this StateFlow to get its state updates
val uiState: StateFlow<LatestNewsUiState> = _uiState
init {
viewModelScope.launch {
newsRepository.favoriteLatestNews
// Update View with the latest favorite news
// Writes to the value property of MutableStateFlow,
// adding a new element to the flow and updating all
// of its collectors
.collect { favoriteNews ->
_uiState.value = LatestNewsUiState.Success(favoriteNews)
}
}
}
}
// Represents different states for the LatestNews screen
sealed class LatestNewsUiState {
data class Success(val news: List<ArticleHeadline>): LatestNewsUiState()
data class Error(val exception: Throwable): LatestNewsUiState()
}
الفئة المسؤولة عن تعديل MutableStateFlow
هي الجهة المنتِجة،
وجميع الفئات التي يتم تحصيلها من StateFlow
هم المستهلِكون. إلغاء الإعجاب
تدفق بارد تم إنشاؤه باستخدام أداة إنشاء flow
، StateFlow
هو ساخن:
الجمع من التدفق إلى تشغيل أي رمز منتج. StateFlow
نشط دائمًا وفي الذاكرة، ويصبح مؤهلاً للنفايات
البيانات فقط عندما لا يكون هناك أي مراجع أخرى لها من المهملات
جذر المجموعة.
عندما يبدأ مستهلك جديد في التجميع من التدفق، يتلقى آخر
في البث وأي حالات لاحقة. يمكنك العثور على هذا السلوك
في الفئات الأخرى القابلة للملاحظة مثل
LiveData
يرصد View
صوت StateFlow
كما هو الحال مع أي مسار آخر:
class LatestNewsActivity : AppCompatActivity() {
private val latestNewsViewModel = // getViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
...
// Start a coroutine in the lifecycle scope
lifecycleScope.launch {
// repeatOnLifecycle launches the block in a new coroutine every time the
// lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
repeatOnLifecycle(Lifecycle.State.STARTED) {
// Trigger the flow and start listening for values.
// Note that this happens when lifecycle is STARTED and stops
// collecting when the lifecycle is STOPPED
latestNewsViewModel.uiState.collect { uiState ->
// New value received
when (uiState) {
is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception)
}
}
}
}
}
}
لتحويل أي مسار إلى StateFlow
، استخدِم
stateIn
الوسيط المتوسط.
StateFlow وFlow وLiveData
StateFlow
وLiveData
لديهما
وأوجه التشابه. كلاهما فئتان لصاحبي بيانات يمكن ملاحظتهما، وكلاهما يتبع
بنمط مشابه عند استخدامه في بنية تطبيقك.
ومع ذلك، تجدر الإشارة إلى أنّ StateFlow
يختلف سلوك استخدام LiveData
:
- تتطلب الدالة
StateFlow
تمرير حالة أولية إلى الدالة الإنشائية، بينما لا يستخدمهاLiveData
. - يلغي
LiveData.observe()
تسجيل المستهلك تلقائيًا عند ينتقل إلى حالةSTOPPED
، بينما يتم جمعه منStateFlow
أو ولن يتوقف أي تدفق آخر عن التجميع تلقائيًا. لتحقيق نفس عليك جمع التدفق منLifecycle.repeatOnLifecycle
حظر.
تشغيل تدفقات باردة ساخنة باستخدام shareIn
StateFlow
هو مسار ساخن، ويبقى في الذاكرة طالما كان التدفق
البيانات المجمّعة أو عندما توجد أي إشارات أخرى إليها من مجموعة البيانات غير المرغوب فيها
جذر. يمكنك زيادة درجة حرارة التدفق البارد باستخدام
shareIn
.
استخدام callbackFlow
التي تم إنشاؤها في تدفقات Kotlin
سبيل المثال، فبدلاً من أن ينشئ كل جامع تدفقًا جديدًا، يمكنك مشاركة
البيانات المأخوذة من Firestore بين التجميعات باستخدام shareIn
.
يجب اجتياز ما يلي:
- تمثّل هذه السمة
CoroutineScope
يتم استخدامه لمشاركة التدفق. يجب أن يكون هذا النطاق أطول من أي مستهلك للحفاظ على التدفق المشترك طالما لزم الأمر. - عدد العناصر المطلوب إعادة تشغيلها لكل جامع جديد.
- سياسة سلوك البدء
class NewsRemoteDataSource(...,
private val externalScope: CoroutineScope,
) {
val latestNews: Flow<List<ArticleHeadline>> = flow {
...
}.shareIn(
externalScope,
replay = 1,
started = SharingStarted.WhileSubscribed()
)
}
في هذا المثال، يعيد مسار latestNews
تشغيل آخر عنصر تم انبعاثه.
لجامع جديد وتظل نشطة طالما أن externalScope
وعلى قيد الحياة وهناك جامعون نشطون. SharingStarted.WhileSubscribed()
سياسة البدء تحافظ على نشاط المنتج الرئيسي أثناء وجوده
المشتركين. تتوفّر سياسات بدء أخرى، مثل
SharingStarted.Eagerly
لبدء تشغيل المنتج فورًا أو
SharingStarted.Lazily
لبدء المشاركة بعد ظهور أول مشترك
والحفاظ على التدفق نشطًا إلى الأبد.
حدث SharedFlow
تعرض الدالة shareIn
المسار SharedFlow
، وهو تدفق ساخن يُصدر قيمًا.
لجميع المستهلكين الذين يجمعون منها. SharedFlow
هو
تعميم StateFlow
قابل للضبط بشكل كبير.
يمكنك إنشاء "SharedFlow
" بدون استخدام "shareIn
". على سبيل المثال،
يمكن استخدام SharedFlow
لإرسال علامات إلى بقية التطبيق بحيث
يتم تحديث كل المحتوى بشكل دوري في نفس الوقت. بصرف النظر عن
وجلب آخر الأخبار، فقد تحتاج أيضًا إلى تحديث المستخدم
المعلومات مع مجموعة الموضوعات المفضلة لديه. في ما يلي
مقتطف الرمز، فإن TickHandler
يعرض SharedFlow
بحيث لا
تعرف الصفوف متى يجب تحديث محتواها. كما هو الحال مع StateFlow
، يمكنك استخدام
خاصية احتياطية من النوع MutableSharedFlow
في فئة لإرسال العناصر
التدفق:
// Class that centralizes when the content of the app needs to be refreshed
class TickHandler(
private val externalScope: CoroutineScope,
private val tickIntervalMs: Long = 5000
) {
// Backing property to avoid flow emissions from other classes
private val _tickFlow = MutableSharedFlow<Unit>(replay = 0)
val tickFlow: SharedFlow<Event<String>> = _tickFlow
init {
externalScope.launch {
while(true) {
_tickFlow.emit(Unit)
delay(tickIntervalMs)
}
}
}
}
class NewsRepository(
...,
private val tickHandler: TickHandler,
private val externalScope: CoroutineScope
) {
init {
externalScope.launch {
// Listen for tick updates
tickHandler.tickFlow.collect {
refreshLatestNews()
}
}
}
suspend fun refreshLatestNews() { ... }
...
}
يمكنك تخصيص سلوك SharedFlow
بالطرق التالية:
- تتيح لك الدالة
replay
إعادة إرسال عدد من القيم المنشورة سابقًا للحصول على المشتركين. - يتيح لك
onBufferOverflow
تحديد سياسة للحالات التي يقع فيها المخزن المؤقت مليئة بالعناصر التي سيتم إرسالها. والقيمة التلقائية هيBufferOverflow.SUSPEND
. مما يجعل المتصل يعلق. تشمل الخيارات الأخرىDROP_LATEST
أوDROP_OLDEST
لدى MutableSharedFlow
أيضًا سمة subscriptionCount
تحتوي على
عدد هواة التجميع النشطين حتى تتمكن من تحسين نشاطك التجاري
المنطق وفقًا لذلك. يحتوي MutableSharedFlow
أيضًا على resetReplayCache
إذا كنت لا ترغب في إعادة تشغيل آخر المعلومات المرسلة إلى التدفق.
موارد التدفق الإضافية
- مسارات Kotlin على Android
- اختبار مسارات Kotlin على Android
- أمور يجب معرفتها عن عاملي التشغيل shareIn وstateIn في Flow
- نقل البيانات من LiveData إلى مسار Kotlin
- مراجع إضافية حول الكوروتينات في لغة Kotlin وتدفق البيانات