簡體   English   中英

從 kotlin 流構建列表

[英]Build a list from kotlin flow

我正在嘗試構建一個應用程序,該應用程序使用從數據層到視圖的 kotlin 流,但在像這樣的簡單問題上掙扎了很多。

我正在從來自我的數據層的 StateFlow 收集整數值,並希望在我將其共享給我視圖模型並通過另一個 StateFlow 查看之前從中構建一個列表。

示例代碼:

class MyDataSource {
    val inputFlow: StateFlow<Int> = TODO()
}

class MyService(
    dataSource: MyDataSource
) {
    private val intList: MutableList<Int> = ArrayList()

    private val _intFlow = MutableStateFlow<List<Int>>(listOf())
    val intFlow: StateFlow<List<Int>> = _intFlow

    init {
        GlobalScope.launch(Dispatchers.IO) {
            dataSource.inputFlow.collect {
                if (!intList.contains(it))
                    intList.add(it)
                
                _intFlow.emit(ArrayList(intList))
            }
        }
    }
}

沒有更好的方法來做到這一點嗎? 就像我錯過的流量運算符? 這看起來特別難看,因為我每次都需要構建一個新的 ArrayList,因為否則即使 List 的內容發生了變化,流也不會發送新值,因為它仍然是同一個 List。

您可以進行一些清理,但我認為流動不斷增長的列表的安排過於具體,無法在核心庫中提供任何一體式解決方案。

  1. 您應該避免使用 GlobalScope 這個服務類應該更合適地擁有自己的范圍,以便您可以在需要時管理生命周期。

  2. 您的支持列表應該是一個集合,因為您實際上是通過在添加對象之前檢查對象是否在其中來將其用作性能不佳的集合。

  3. 使用鏈運算符和stateIn而不是操作 MutableStateFlow 並且必須使用支持屬性會更干凈。

class MyService(
    dataSource: MyDataSource
) {
    private val intSet = mutableSetOf<Int>()
    private val scope = CoroutineScope(Dispatchers.Default)

    val intFlow = dataSource.inputFlow
        .map {
            intSet += it
            intSet.toList()
        }.stateIn(scope, SharingStarted.Eagerly, emptyList())
}

編輯:這是在每次迭代中避免設置到列表副本和新分配的未經測試的嘗試:

class MyService(
    dataSource: MyDataSource
) {
    private val intSet = mutableSetOf<Int>()
    private var currentList = mutableListOf<Int>()
    private var previousList = mutableListOf<Int>()
    private var lastEmittedValue: Int? = null
    private val scope = CoroutineScope(Dispatchers.Default)

    val intFlow = dataSource.inputFlow
        .mapNotNull { newValue ->
            if (!intSet.add(newValue)) 
                return@mapNotNull null
            lastEmittedValue?.let {
                previousList += it
            } // both backing lists now identical
            lastEmittedValue = newValue
            previousList = currentList.also { currentList = previousList }
            // previousList is the one missing lastEmittedValue on next iteration:
            currentList += newValue
            currentList
        }.stateIn(scope, SharingStarted.Eagerly, emptyList())
}

scan是否滿足您的需求?

從文檔:

使用操作折疊給定的流,發出每個中間結果,包括初始值。 [...] 例如:

flowOf(1, 2, 3).scan(emptyList<Int>()) { acc, value -> acc + value }.toList()將產生[], [1], [1, 2], [1, 2, 3]]

https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/scan.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM