【2025最新版Kotlin教程】Kotlin第一行代码系列第二十课-协程Flow

99 阅读1分钟
【2025最新版Kotlin教程】Kotlin第一行代码系列第二十课-协程Flow

Flow 极其强大,可以说用的好Flow才算真正掌握协程。 它比Channel用的场景多,因为它传输数据过程中可以改变。
使用场景:复杂的异步场景,我们就可以使用 Flow

中间操作符:可以说集合有的,它都有

简单示例代码:
fun main() {

    // 方式1:flow 用emit发送数据
    runBlocking {
        flow{
            emit(1)
            emit(2)
            emit(3)
            emit(4)
            emit(5)
        }.filter { it > 2 }
            .take(2)
            .collect {
                println(it)
            }
    }

    // 方式2:flowOf()
    runBlocking {
        flowOf(1, 2, 3, 4, 5)
            .filter { it > 2 }
            .map { it * 2 }
            .take(2)
            .collect {
                println(it)
            }
    }

    // 方式3:asFlow()
    runBlocking {
        listOf(1, 2, 3, 4, 5)
            .asFlow()
            .filter { it > 2 }
            .map { it * 2 }
            .take(2)
            .collect {
                println(it)
            }
    }

    /**
     * 注意:中间操作符,有顺序的
     * 下面代码就什么也没接收到
     */
    runBlocking {
        flowOf(1, 2, 3, 4, 5)
            .take(2)
            .filter { it > 2 }
            .map { it * 2 }
            .collect {
                println(it)
            }
    }

    /**
     * onStart,onnCompletion,异常捕获就不说了
     */

    //===================================== flow的线程切换 =============================================================

    // 关键字 flowOn ,影响到它之前的操作符
    runBlocking {
        flowOf(11, 22, 33, 44, 55)
            .filter {
                println("Coroutine in filter:${Thread.currentThread().name}")
                it > 2
            }
            .flowOn(Dispatchers.IO)
            .take(2)
            .map {
                println("Coroutine in Map:${Thread.currentThread().name}")
                it * 2
            }
            .collect {
                println("Coroutine in collect:${Thread.currentThread().name}")
                println(it)
            }
    }

    // 关键字 launchIn
    // 代表整个flow在那线程运行,如果你要某处上游在那线程运行在独自调flowOn
    val mySingleDispatcher = Executors.newSingleThreadExecutor {
        Thread(it, "MySingleThread").apply { isDaemon = true }
    }.asCoroutineDispatcher()

    val scope = CoroutineScope(mySingleDispatcher)

    runBlocking {
        flow{
            emit(1111)
            emit(2222)
            emit(3333)
            emit(4444)
            emit(5555)
        }
            .filter {
                println("Coroutine in filter 1111:${Thread.currentThread().name}")
                it > 2
            }
            .flowOn(Dispatchers.IO)
            .take(2)
            .map {
                println("Coroutine in map 1111 :${Thread.currentThread().name}")
                it * 2
            }
            .flowOn(Dispatchers.Default)
            .onEach {
                println("Coroutine in each 1111:${Thread.currentThread().name}")
                println(it)
            }
            .launchIn(scope)


    }


    // 如果我想collect里面切换线程呢,用withContext{}
    /**
     * 注意flow里面就不提倡用用withContext了
     */
    runBlocking {
        flowOf(111, 222, 333, 444, 555)
            .filter {
                it > 2
            }
            .flowOn(Dispatchers.IO)
            .take(2)
            .map {
                it * 2
            }
            .collect {
                withContext(Dispatchers.IO){
                    println("Coroutine in collect:${Thread.currentThread().name}")
                    println(it)
                }
            }
    }

   // ============================================ flow终止符 ======================================================
    // 终止符有 first()、single()、fold{}、reduce{},toList()

    // =============================================== flow是冷和懒的 ==============================================
    /**
     * 表现在没有终止符,我是不发送的
     * 我是一条条数据发送的
     */

}
整个kotlin教程的源码项目结构图:

在这里插入图片描述\