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") // Καταγραφή του νήματος όπου ξεκινάει ο builder του flow
    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("Ξεκίνησε ο builder του Flow") // Θα λειτουργεί στο πρώτο καθορισμένο flowOn
    emit("A")
    emit("B")
}.map {
    logThread("Χαρτογράφηση $it") // Θα λειτουργεί στο δεύτερο καθορισμένο flowOn
    it.toLowerCase()
}.flowOn(Dispatchers.Default) // Το δεύτερο flowOn επηρεάζει το map() και τον builder του flow
.filter {
    logThread("Φιλτράρισμα $it") // Θα λειτουργεί στο νήμα από το οποίο καλείται το `collect` (κατά κανόνα main/runBlocking)
    true
}.flowOn(Dispatchers.IO) // Το πρώτο flowOn επηρεάζει το map() και τον builder του flow

fun main() = runBlocking {
    simpleFlowWithMultipleFlowOn().collect { value ->
        logThread("Συλλεγμένο $value") // Λειτουργεί στο νήμα runBlocking (main)
    }
}

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

Σε αυτό το παράδειγμα:

  • Ο builder του flow και το map θα λειτουργούν στο Dispatchers.Default (επειδή αυτός είναι ο τελευταίος flowOn στη σειρά πριν από αυτούς).
  • Το filter θα λειτουργεί στο νήμα από το οποίο καλείται το collect, δηλαδή στο νήμα όπου εκτελείται το runBlocking (συνήθως Main στο Android).

Είναι σημαντικό να καταλάβετε ότι το flowOn δημιουργεί ένα ενδιάμεσο buffer και δεν αποτελεί "διαφανή" αλλαγή νήματος.