Как передать значение потока из другой функции? Котлинские сопрограммы
У меня есть поток:
val myflow = kotlinx.coroutines.flow.flow<Message>{}
и хотите испускать значения с помощью функции:
override suspend fun sendMessage(chat: Chat, message: Message) {
myflow.emit(message)
}
Но компилятор не позволяет мне этого сделать, есть ли обходные пути для решения этой проблемы?
5 ответов
Ответ Анимеш Саху в значительной степени верен. Вы также можете вернуть канал в виде потока (см. ConsumerAsFlow или asFlow в BroadcastChannel).
Но есть еще кое-что под названием StateFlow
в настоящее время разрабатывается командой Kotlin, которая частично предназначена для реализации аналогичного поведения, хотя неизвестно, когда оно будет готово.
Вы можете использовать StateFlow для такого случая использования. Вот пример кода.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
val chatFlow = MutableStateFlow<String>("")
fun main() = runBlocking {
// Observe values
val job = launch {
chatFlow.collect {
print("$it ")
}
}
// Change values
arrayOf("Hey", "Hi", "Hello").forEach {
delay(100)
sendMessage(it)
}
delay(1000)
// Cancel running job
job.cancel()
job.join()
}
suspend fun sendMessage(message: String) {
chatFlow.value = message
}
Вы можете протестировать этот код, выполнив приведенный ниже фрагмент.
<iframe src="https://pl.kotl.in/DUBDfUnX3" style="width:600px;"></iframe>
Поток является самодостаточным, как только блок (лямбда) внутри потока выполняется, поток заканчивается, вы должны выполнять операции внутри и отправлять их оттуда.
Вот аналогичная проблема с github:
Afaik Flow спроектирован как автономный, воспроизводимый, холодный поток, поэтому эмиссия за пределами его собственной области не будет частью контракта. Я думаю, что вы ищете канал.
И IMHO вы, вероятно, смотрите на каналы или, в частности, на ConflatedBroadcastChannel для нескольких приемников. Разница между обычным каналом и широковещательным каналом заключается в том, что несколько получателей могут прослушивать широковещательный канал с помощью функции openSubscription, которая возвращает ReceiveChannel, связанный с BroadcastChannel.
Использовать
SharedStateFlow
в нем есть все, что вам нужно.
Инициализация вашего потока:
val myFlow = MutableSharedFlow<Message>()
и теперь он должен работать так же, как вы пытались раньше:
override suspend fun sendMessage(chat: Chat, message: Message) {
myFlow.emit(message)
}
Вам нужен такой канал:
private val _navigationAction = Channel<Route>(Channel.CONFLATED)
override val navigationAction : Flow<Route> = _navigationAction.receiveAsFlow()
override fun navigateTo(target: Route) {
_navigationAction.trySend(target)
}