StateFlow ve SharedFlow

StateFlow ve SharedFlow Akış API'leridir akışların en uygun şekilde durum güncellemelerini ve birden çok kullanıcıya değer yayan yardımcı olur.

StateFlow

StateFlow geçerli ve yeni durum yayan, durum sahibi gözlemlenebilir bir akıştır güncellemelerine göz atacağız. Geçerli durum değeri, value Durumu güncellemek ve akışa göndermek için şuna yeni bir değer atayın: öğesinin value özelliği MutableStateFlow sınıfı.

Android'de StateFlow, bakımını yapması gereken sınıflar için bir değişiklik gösterebilir.

Kotlin akışlarına ilişkin örneklerde, bir StateFlow View'ın bunu yapabilmesi için,LatestNewsViewModel kullanıcı arayüzü durumu güncellemelerini dinleme ve doğası gereği ekran durumunun yapılandırma değişiklikleridir.

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 öğesinin güncellenmesinden sorumlu sınıf yapımcıdır, ve StateFlow verisinden toplanan tüm sınıflar tüketicidir. Beğenmeyi kaldır flow oluşturucu kullanılarak oluşturulan soğuk akış, StateFlow sıcaktır: bir üretici kodunu tetiklemez. StateFlow her zaman etkin ve bellektedir ve çöpe atılmaya uygun hale gelir. yalnızca bir çöpten başka bir referans olmadığında koleksiyonu koleksiyon kökü.

Yeni bir tüketici akıştan veri toplamaya başladığında, ilk olarak durumundaki durumu ve sonraki durumları gösterir. Bu davranışı, diğer gözlemlenebilir sınıflarda LiveData.

View, diğer akışlarda olduğu gibi StateFlow öğesini dinler:

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)
                    }
                }
            }
        }
    }
}
ziyaret edin.

Herhangi bir akışı StateFlow biçimine dönüştürmek için stateIn ara operatör.

StateFlow, Flow ve LiveData

StateFlow ve LiveData irdeleyelim. Her ikisi de gözlemlenebilir veri sahibi sınıflarıdır ve her ikisi de benzer bir kalıpla karşılaşabilirsiniz.

Ancak StateFlow ve LiveData farklı davranır:

  • StateFlow, oluşturucuya bir başlangıç durumunun iletilmesini gerektirir. ancak LiveData bunu yapmaz.
  • LiveData.observe(), görünümü STOPPED durumuna geçerken StateFlow veya diğer akışlar otomatik olarak toplanmaya son vermez. Aynı hedefe ulaşmak için akışını bir Lifecycle.repeatOnLifecycle verisinden toplamanız gerekir. engelleyebilirsiniz.

Soğuk akışları shareIn kullanarak ısıtma

StateFlow, sıcak bir akıştır. Akış olduğu sürece bellekte kalır veya bu verilere ilişkin diğer referanslar bir atık koleksiyonunda bulunuyorsa kök. Soğuk akışları sıcak duruma getirmek için shareIn operatörümüzü kullanabilirsiniz.

Kotlin akışlarında oluşturulan callbackFlow öğesini bir her koleksiyoncunun yeni bir akış oluşturmasını istemek yerine, shareIn kullanılarak toplayıcılar arasında Firestore'dan alınan veriler. Şu belgeleri geçmeniz gerekir:

  • Akışı paylaşmak için kullanılan bir CoroutineScope. Bu kapsam, şu anki ihtiyaç kadar uzun tutmaktır.
  • Her yeni koleksiyoncu için tekrar oynatılacak öğe sayısı.
  • Başlangıç davranışı politikası.
class NewsRemoteDataSource(...,
    private val externalScope: CoroutineScope,
) {
    val latestNews: Flow<List<ArticleHeadline>> = flow {
        ...
    }.shareIn(
        externalScope,
        replay = 1,
        started = SharingStarted.WhileSubscribed()
    )
}

Bu örnekte, latestNews akışı yayınlanan son öğeyi tekrar oynatır yeni bir toplayıcıya gönderir ve externalScope olduğu sürece etkin kalır. hâlâ canlı olduğunu ve etkin koleksiyoncuların bulunduğunu gösteriyor. SharingStarted.WhileSubscribed() başlatma politikası etkin olduğunda yukarı akış üreticisini etkin tutar abone. Şu gibi başka başlangıç politikaları da kullanılabilir: SharingStarted.Eagerly yazarak yapımcıyı hemen başlatabilirsiniz. İlk abone gösterildikten sonra paylaşmaya başlamak için SharingStarted.Lazily ve akışın sonsuza kadar etkin olmasını sağlayın.

SharedFlow

shareIn işlevi, değerler yayan bir sıcak akış olan SharedFlow döndürür. tüm tüketicilerin kullanımına sunuyor. SharedFlow, StateFlow öğesinin yüksek düzeyde yapılandırılabilir genelleştirilmesi.

shareIn kullanmadan bir SharedFlow oluşturabilirsiniz. Örneğin, uygulamanın geri kalanına işaret göndermek için bir SharedFlow kullanabilir tüm içerik düzenli aralıklarla aynı anda yenilenir. Şu bölgelerden: en son haberleri almak için, kullanıcıyı bilgilendirmek, bilgi bölümünde bulabilirsiniz. Sonraki kod snippet'i kullanıyorsanız TickHandler bir SharedFlow gösterir. Böylece diğer içeriğini ne zaman yenilemesi gerektiğini bilir. StateFlow konusunda olduğu gibi, bir sınıfta öğe göndermek için MutableSharedFlow türündeki yedekleme özelliği akışla aynıdır:

// 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 davranışını aşağıdaki şekillerde özelleştirebilirsiniz:

  • replay, yeni reklam öğesi için önceden yayınlanmış birkaç değeri yeniden göndermenize abone.
  • onBufferOverflow, tampon ya da esneme payının ne zaman gönderilecek öğe dolu. Varsayılan değer BufferOverflow.SUSPEND ise bu da arayanı askıya alır. Diğer seçenekler: DROP_LATEST veya DROP_OLDEST.

MutableSharedFlow, şunu da içeren bir subscriptionCount özelliğine sahip: İşletmenizi optimize edebilmek için etkin toplayıcıların sayısını ve mantığı buna göre şekillendirebilir. MutableSharedFlow, bir resetReplayCache içeriyor işlevini kullanabilirsiniz.

Ek akış kaynakları