Sobes.tech
Middle

Чӣ гуна метавон дар Flow ҷараёнҳоро иваз кард? Flow дар кадом ҷараён кор мекунад?

sobes.tech AI

Ҷавоб аз AI

По подразбиране Flow работи на нишката, от която е стартиран. Превключването на нишки може да се извърши с помощта на оператора flowOn.

import kotlinx.coroutines.CoroutineDispatcher // За CoroutineDispatcher
import kotlinx.coroutines.Dispatchers // За Dispatchers
import kotlinx.coroutines.flow.Flow // За Flow
import kotlinx.coroutines.flow.flow // За flow
import kotlinx.coroutines.flow.flowOn // За flowOn
import kotlinx.coroutines.runBlocking // За runBlocking

// Примерна функция, която връща Flow
fun simpleFlow(): Flow<Int> = flow {
    logThread("Flow започна") // Логиране на нишката, където се стартира flow builder
    for (i in 1..3) {
        emit(i) // Изпращане на стойности
    }
}

fun main() = runBlocking {
    simpleFlow()
        .flowOn(Dispatchers.IO) // Превключваме upstream (емитерите) на Dispatchers.IO
        .collect { value ->
            logThread("Събрано $value") // Логиране на нишката, където се събират стойностите
        }
}

// Помощна функция за логиране на нишка
fun logThread(msg: String) {
    println("[$msg] [${Thread.currentThread().name}]")
}

Операторът flowOn влияе на нишката, на която се изпълняват оператори преди него в веригата (включително flow builder). Операторите след flowOn се изпълняват на нишката, посочена в аргумента flowOn. Ако в веригата има няколко flowOn, всеки от тях влияе на частта от веригата преди него.

Пример с няколко flowOn:

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking

fun simpleFlowWithMultipleFlowOn(): Flow<String> = flow {
    logThread("Flow builder започна") // Ще работи на първия посочен flowOn
    emit("A")
    emit("B")
}.map {
    logThread("Mapиране $it") // Ще работи на втория посочен flowOn
    it.toLowerCase()
}.flowOn(Dispatchers.Default) // Вторият flowOn влияе на map() и flow builder
.filter {
    logThread("Филтриране $it") // Ще работи на нишката, от която се извиква collect (обикновено main/runBlocking)
    true
}.flowOn(Dispatchers.IO) // Първият flowOn влияе на map() и flow builder

fun main() = runBlocking {
    simpleFlowWithMultipleFlowOn().collect { value ->
        logThread("Събиране $value") // Работи на нишката runBlocking (main)
    }
}

fun logThread(msg: String) {
    println("[$msg] [${Thread.currentThread().name}]")
}

В този пример:

  • flow builder и map ще работят на Dispatchers.Default (защото е последният flowOn в веригата преди тях).
  • filter ще работи на нишката, от която се извиква collect, тоест на нишката, където се изпълнява runBlocking (обикновено Main в Android).

Важно е да се разбере, че flowOn създава междинен буфер и не е "прозрачно" превключване.