流组合不会触发,但收集会触发

问题描述 投票:0回答:1

我有一个典型的 Android MVVM 项目(Compose -> ViewModel -> Repository -> RoomDB),并在下面的演示中简化了概念。

我想实现什么目标?: 我想从我的存储库中的 Room Dao (@Query(...) fun getAll(): Flow) 读取两个流。它们应该组合成一个流,然后返回到我的 viewModel。 我想将 viewModel 中的流转换为 StateFlow,只要 viewModel 存在,它就可以进行观察。在下面的示例中,我将此 StateFlow 值传播到可变状态“项目”,以便能够在 UI 中显示值以进行演示。

问题: 当我尝试调试时,流上的组合方法不会触发层次结构中备份的任何更改,单个 Dao 流上的collectLatest也不会触发。有趣的是,collect 确实...

现在开始演示:


class ViewModel(private val coroutineScope: CoroutineScope) {

    private val repository = Repository()

    val item = mutableStateOf<String?>(null)

    init {
        coroutineScope.launch {
            repository.item.stateIn(coroutineScope).collect {
                item.value = it
            }
        }
    }

    fun click() {
        coroutineScope.launch {
            repository.increaseItem()
        }
    }
}

class Repository {
    private val dao = Dao()

    val item: Flow<String> = flow {
        // This does NOT trigger
        dao.dbItem.combine(dao.dbItem2) { value1, value2 ->
            emit("$value1|$value2")
        }

        // This does NOT trigger
//        dao.dbItem.collectLatest {
//            emit(it)
//        }

        // This does trigger...
//        dao.dbItem.collect {
//            emit(it)
//        }
    }

    suspend fun increaseItem() = dao.increaseDbItem()
}

class Dao {

    val dbItem = MutableStateFlow("0")
    val dbItem2 = MutableStateFlow("A")

    suspend fun increaseDbItem() {
        dbItem.emit("${dbItem.value} 0")
        dbItem2.emit("${dbItem2.value} A")
    }
}

@Composable
fun AtteTest() {
    val coroutineScope = rememberCoroutineScope()
    val viewModel = ViewModel(coroutineScope)

    TestAppTheme {
        Surface {
            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
                        Text("Value:")
                        Text(viewModel.item.value ?: "")
                    }
                    Button(onClick = {
                        viewModel.click()
                    }) {
                        Text(text = "click")
                    }
                }
            }
        }
    }
}

@Preview
@Composable
fun PreviewAtteTest() {
    AtteTest()
}
android kotlin-coroutines dao stateflow
1个回答
0
投票

进行以下更改后即可工作:
返回联合收割机而不是包含联合收割机的新流

class Repository {
private val dao = Dao()

val item: Flow<String> = dao.dbItem2.combine(dao.dbItem) { value1, value2 ->
    "$value1|$value2"
}

suspend fun increaseItem() = dao.increaseDbItem()
}

通过将流更改为回调流解决了collectLatest的问题:

 val item: Flow<String> = callbackFlow {
    dao.dbItem.collectLatest {
        send(it)
    }
    awaitClose {  }
}
© www.soinside.com 2019 - 2024. All rights reserved.