• Paul Shan
    2022-03-24
    思考题:flow本身已经提供了线程切换的中间操作符flowOn和launchIn,来确定不同部分的线程边界并优化,withContext要再次切换线程,势必打破flow规划好的线程边界,估计要出错,抛出异常来提前报错。

    作者回复: 没错,是这个意思。

    
    11
  • 曾帅
    2022-03-10
    关于思考题,翻了一下 emit() 的代码,发现里面有说到这一点。 里面说不允许在 withContext 里 调用 emit() 是因为 emit() 默认不是线程安全的,而且还给出了一种解决方案,那就是使用 channel 来处理。

    作者回复: 能从源码中找到证据,很好。

    
    3
  • 魏全运
    2022-03-04
    Flow 跟RxJava 的使用方式太像了

    作者回复: 思想是类似的,但Flow的操作符比RxJava还是要少很多的。所以会更容易上手一些。

    共 3 条评论
    2
  • Paul Shan
    2022-03-24
    原来在使用Rxjava还是Coroutine的时候,我还是支持使用Rxjava的,Flow出来之后,我就倒向Coroutine Flow。

    作者回复: 是的,Flow的学习成本会更低一些。

    
    1
  • 白乾涛
    2022-03-12
    以下代码,为啥没有任何日志输出? 而且,为啥程序不会结束? fun main() = runBlocking { withContext(dispatcher) { flow { log("emit"); emit(1) } .flowOn(Dispatchers.Main) .filter { log("filter"); it > 0 } .collect { log("collect") } } }

    作者回复: 我在第17讲当中提到过,在非UI平台上,Dispatchers.Main是没有意义的。只有在Android、Swing之类的平台,我们才可以使用Dispatchers.Main。

    
    1
  • pengzhaoyang code...
    2022-04-01
    发送的数据必须来自同一个协程内,不允许来自多个CoroutineContext,所以默认不能在flow{}中创建新协程或通过withContext()切换协程。如需切换上游的CoroutineContext,可以通过flowOn()进行切换

    作者回复: 是的,那么,为什么不允许多个CoroutineContext?

    
    
  • Paul Shan
    2022-03-24
    Flow也有热的SharedFlow,还支持一对多的服务,我自己的经验是,Channel在具体场景中基本可以被Flow替代,而且更方便更安全。

    作者回复: 是的,Channel更像是一个底层的基础工具,不太适合直接拿来用。

    
    
  • 梁中华
    2022-03-22
    大佬,能结合几个服务端的例子讲讲不,其实协程的主要发挥场景还是在服务端,就像gorouting一样

    作者回复: 感谢你的建议,我会考虑的。

    
    
  • dawn
    2022-03-16
    大佬,为什么下面的代码没法结束 fun main() { val asCoroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher() val scope = CoroutineScope(asCoroutineDispatcher) runBlocking { flow { emit(1f) emit("s") kotlinx.coroutines.delay(2000) emit(2f) emit(3f) // throw NullPointerException() emit(4f) emit(5f) logX("emit") }.filter { logX("filter") it is Float }.onStart { logX("onStart") }.onCompletion { logX("onCompletion") }.catch { logX("catch $it") }.onEach { logX(it) }.launchIn(scope) logX("end") } }

    作者回复: 其实是因为:你代码中的Dispatcher对应的线程池没有定义成守护线程。 ``` fun main() { // 请留意 Dispatcher 当中的isDaemon = true val mySingleDispatcher = Executors.newSingleThreadExecutor { Thread(it, "MySingleThread").apply { isDaemon = true } }.asCoroutineDispatcher() val scope = CoroutineScope(mySingleDispatcher) runBlocking { flow { emit(1f) emit("s") kotlinx.coroutines.delay(2000) emit(2f) emit(3f) // throw NullPointerException() emit(4f) emit(5f) logX("emit") }.filter { logX("filter") it is Float }.onStart { logX("onStart") }.onCompletion { logX("onCompletion") }.catch { logX("catch $it") }.onEach { logX(it) }.launchIn(scope) logX("end") } } ```

    共 2 条评论
    
  • 白乾涛
    2022-03-12
    为啥下面代码中的 emit 也执行在 IO 线程? fun main() = runBlocking { val flow = flow { log("emit"); emit(1) } withContext(Dispatchers.IO) { flow.filter { log("filter"); it > 0 } .collect { log("collect") } } }

    作者回复: 这很合理,在默认情况下,emit是会使用collect的协程上下文的。

    共 3 条评论
    