协程中的自定义拦截器

Custom interceptors in coroutines

我已经熟悉协程的 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 键指定为 ContinuationInterceptor.Key

因此协程不应将其识别为拦截器。

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

我想知道:

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

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

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

我修复了您的代码中的一些明显问题,例如 return 每次都从 key 获取一个新对象,而不是实现 equals。我 return 一个单身人士,所以默认 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]

第一行向您展示了行为应该是什么,第二行展示了您的实施情况。你打破了平等关系。我没明白为什么。

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