Middle
Ako možno prepínať vlákna v Flow? Na ktorom vlákne beží Flow?
sobes.tech AI
Odpoveď od AI
Podľa predvoleného nastavenia Flow beží na vlákne, z ktorého bol spustený. Prepnúť vlákna je možné pomocou operátora flowOn.
import kotlinx.coroutines.CoroutineDispatcher // Pre CoroutineDispatcher
import kotlinx.coroutines.Dispatchers // Pre Dispatchers
import kotlinx.coroutines.flow.Flow // Pre Flow
import kotlinx.coroutines.flow.flow // Pre flow
import kotlinx.coroutines.flow.flowOn // Pre flowOn
import kotlinx.coroutines.runBlocking // Pre runBlocking
// Príklad funkcie, ktorá vracia Flow
fun simpleFlow(): Flow<Int> = flow {
logThread("Flow začal") // Logovanie vlákna, kde sa spúšťa flow builder
for (i in 1..3) {
emit(i) // Emitovanie hodnôt
}
}
fun main() = runBlocking {
simpleFlow()
.flowOn(Dispatchers.IO) // Prepneme upstream (emittery) na Dispatchers.IO
.collect { value ->
logThread("Zbierané $value") // Logovanie vlákna, kde sa zbierajú hodnoty
}
}
// Pomocná funkcia na logovanie vlákna
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
Operátor flowOn ovplyvňuje vlákno, na ktorom sú vykonávané operátory pred neho v reťazci (vrátane flow builderu). Operátory za flowOn sa vykonávajú na vlákne uvedenom v argumente flowOn. Ak je v reťazci viac flowOn, každý z nich ovplyvňuje časť reťazca pred ním.
Príklad s viacerými flowOn:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
fun simpleFlowWithMultipleFlowOn(): Flow<String> = flow {
logThread("Flow builder začal") // Bude bežať na prvom špecifikovanom flowOn
emit("A")
emit("B")
}.map {
logThread("Mapovanie $it") // Bude bežať na druhom špecifikovanom flowOn
it.toLowerCase()
}.flowOn(Dispatchers.Default) // Druhý flowOn ovplyvňuje map() a flow builder
.filter {
logThread("Filtrovanie $it") // Bude bežať na vlákne, z ktorého sa volá collect (zvyčajne main/runBlocking)
true
}.flowOn(Dispatchers.IO) // Prvý flowOn ovplyvňuje map() a flow builder
fun main() = runBlocking {
simpleFlowWithMultipleFlowOn().collect { value ->
logThread("Zbieranie $value") // Beží na vlákne runBlocking (main)
}
}
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
V tomto príklade:
flowbuilder amapbudú bežať naDispatchers.Default(pretože je to poslednýflowOnv reťazci pred nimi).filterbude bežať na vlákne, z ktorého sa volácollect, teda na vlákne, kde sa vykonávarunBlocking(zvyčajne Main v Androidu).
Dôležité je pochopiť, že flowOn vytvára medzičasový buffer a nie je "priehľadným" prepínaním.