a284628487 / AndroidPoint

Android Note
1 stars 0 forks source link

Kotlin Coroutine & Flow #13

Open a284628487 opened 3 years ago

a284628487 commented 3 years ago

Flow

Flow.collect,每次执行 collect 都会触发flow提供者代码。

    @Test
    fun flowTest() {
        val flow = flow<String> {
            delay(1000)
            println("emit 1 ${this.hashCode()}")
            emit("${System.currentTimeMillis()}")
            delay(1000)
            println("emit 2 ${this.hashCode()}")
            emit("${System.currentTimeMillis()}")
        }
        runBlocking {
            val l = flow.take(1)
            println("------ take(1) collect 1 ------")
            l.collect()
            println("------ take(1) collect 2 ------")
            l.collect()

            println("------ collect 1 ------")
            flow.collect()
            println("------ collect 2 ------")
            flow.collect()

            println("------ Flow Collect End ------")
        }
    }

输出:

------ take(1) collect 1 ------
emit 1 398887205
------ take(1) collect 2 ------
emit 1 1121172875
------ collect 1 ------
emit 1 649734728
emit 2 649734728
------ collect 2 ------
emit 1 1595953398
emit 2 1595953398
------ Flow Collect End ------
a284628487 commented 3 years ago
  1. supervisorScope 构造块下启动的 coroutine ,失败或者异常 不会 影响其它coroutine的执行。
  2. coroutineScope 构造块下启动的 coroutine ,失败或者异常 影响其它coroutine的执行。

        runBlocking {
            CoroutineScope(Job()).launch {
                supervisorScope {
                    launch {
                        delay(1000)
                        println("I'm launch 1")
                        throw RuntimeException("what")
                    }
                    launch {
                        delay(1200)
                        println("I'm launch 2") // 会被执行
                    }
                }
            }.join()
    
            CoroutineScope(Job()).launch {
                coroutineScope {
                    launch {
                        delay(1000)
                        println("I'm launch 3")
                        throw RuntimeException("what")
                    }
                    launch {
                        delay(1200)
                        println("I'm launch 4") // 不会被执行
                    }
                }
            }.join()
        }

CoroutineScope(Job()).launch 可修改成直接 launch ,区别是前者的执行协程是 "DefaultDispatcher-worker-2 @coroutine#xx" ,而后者是 "main @coroutine#xx"

a284628487 commented 3 years ago

Dispatcher

supervisiorScopecoroutineScope 构建块创建Scope,Scope 的Dispatcher继承自外部Scope。

        runBlocking {
            supervisorScope { // or coroutineScope
                try {
                    getInteger(1000)
                } catch (e: Exception) {
                    println("e1: ${e}")
                }
                val i = getInteger(2000)
                println("result1 = $i, ${Thread.currentThread().name}")
            }

            CoroutineScope(currentCoroutineContext()).launch {
                try {
                    getInteger(1000)
                } catch (e: Exception) {
                    println("e3: ${e}")
                }
                val i = getInteger(2000)
                println("result3 = $i, ${Thread.currentThread().name}")
            }.join()
        }

可以使用 currentCoroutineContext() 将当前Scope的Dispatcher传给CoroutineScope。上面的示例2中,执行协程的Diaptcher仍然是外部的Scope。

输出:


            throw exception
            e1: java.lang.RuntimeException: what
            result1 = 2000, main @coroutine#1

            throw exception
            e3: java.lang.RuntimeException: what
            result3 = 2000, main @coroutine#3

CoroutineScope 创建的Scope,默认分配到 Dispatchers.Default

        runBlocking {
            CoroutineScope(SupervisorJob()).launch {
                try {
                    getInteger(1000)
                } catch (e: Exception) {
                    println("e2: ${e}")
                }
                val i = getInteger(2000)
                println("result2 = $i, ${Thread.currentThread().name}")
            }.join()

            CoroutineScope(Job()).launch {
                try {
                    getInteger(1000)
                } catch (e: Exception) {
                    println("e4: ${e}")
                }
                val i = getInteger(2000)
                println("result4 = $i, ${Thread.currentThread().name}")
            }.join()
        }

输出:

            throw exception
            e2: java.lang.RuntimeException: what
            result2 = 2000, DefaultDispatcher-worker-1 @coroutine#2

            throw exception
            e4: java.lang.RuntimeException: what
            result4 = 2000, DefaultDispatcher-worker-1 @coroutine#4