【问题标题】:Custom interceptors in coroutines协程中的自定义拦截器
【发布时间】:2021-12-29 03:37:17
【问题描述】:

我已经熟悉了协程的 ContinuationInterceptor 部分 我写了下面这段代码来验证我的想法

class MyContext: CoroutineContext.Element{
    override val key : CoroutineContext.Key<*>
    get() = object : CoroutineContext.Key<MyContext>{}
}

val myInterceptor = object : ContinuationInterceptor {
    //Key is set to a non-interceptor type
    override val key : CoroutineContext.Key<MyContext>
    get() = object : CoroutineContext.Key<MyContext>{}

    override fun <T> interceptContinuation(continuation: 
        Continuation<T>): Continuation<T> {
        Log.i(TAG,"interceptor:"+continuation.context[CoroutineName].toString())
        return Continuation(EmptyCoroutineContext) {
            thread(name = "myThread") {
                continuation.resumeWith(it)
            }
        }
    }
}

lifecycleScope.launch(myInterceptor + CoroutineName("MY1")) {
    Log.i(TAG,"MY1 start:"+Thread.currentThread().name)
    fun1()

    launch(CoroutineName("MY2")) {
        Log.i(TAG,"MY2 run:"+Thread.currentThread().name)
    }
    withContext(Dispatchers.Main+CoroutineName("MY3")) {
        Log.i(TAG,"MY3 run:"+Thread.currentThread().name)
    }
    Log.i(TAG,"MY1 end:"+Thread.currentThread().name)
}

我没有将 myInterceptor Key 指定为 ContinuationInterceptor.Key

所以协程不应该将其识别为拦截器。

MY1MY2 证明了这个想法,但是MY3myInterceptor 拦截并在新线程中运行。

我想知道:

  1. 为什么myInterceptor被识别为拦截器

  2. 为什么Dispatcher.Main 不起作用

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    所示代码的行为很奇怪。我找不到确切的原因。

    我修复了您的代码的一些明显问题,例如每次都从key 返回一个新对象,并且没有实现equals。我返回一个单例,所以默认的 equals 有效:

    class MyContext: CoroutineContext.Element {
        companion object Key : CoroutineContext.Key<MyContext>
        override val key: CoroutineContext.Key<MyContext> = Key
    }
    
    val myInterceptor = object : ContinuationInterceptor {
        override val key: CoroutineContext.Key<MyContext> = MyContext.Key
    
        override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> {
            println("interceptContinuation: ${continuation.context[CoroutineName]?.name}")
            return Continuation(EmptyCoroutineContext) {
                thread(name = "myThread") {
                    continuation.resumeWith(it)
                }
            }
        }
    
        override fun toString() = "My Interceptor"
    }
    

    不过,这些修复并没有改变行为,而且我们甚至可以在扰乱调度之前看到它已被破坏:

    val goodCtx = CoroutineName("A") + CoroutineName("B")
    val badCtx = myInterceptor + myInterceptor
    println(goodCtx)
    println(badCtx)
    

    打印出来

    CoroutineName(B)
    [My Interceptor, My Interceptor]
    

    第一行显示行为应该是什么,第二行显示你的实现是什么。你打破了平等关系。我不明白为什么。

    即使这个发现并不能直接解释你的拦截器最终是如何被使用的,但它确实让你了解当你违背作者的意图使用框架时会发生什么样的事情。

    【讨论】:

    • LOL,我故意违背了框架的意图,也许时间不应该浪费在这样的错误行为上
    • 是的,很明显你是故意的。在某种程度上,我认为这样的探索是有效的,行为应该更有意义。另一方面,我敢打赌 Kotlin Coroutines 团队有更好的方式来投入时间和精力,而不是在他们不感兴趣的情况下纠正行为。
    猜你喜欢
    • 1970-01-01
    • 2020-10-11
    • 1970-01-01
    • 2018-05-25
    • 1970-01-01
    • 2020-11-20
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多