如何将协程直接分派到JVM上的主线程?

时间:2019-01-15 01:28:59

标签: kotlin kotlinx.coroutines

我正在为jvm建立一个基于kotlin协程的网络框架。 Client和Server类实现CoroutineScope,而coroutinecontext的替代项是Dispatchers.IO,因为我很确定这是在这种情况下使用的正确Dispatcher。但是,我希望处理主线程上的读取数据包,或者至少提供该选项。在不阅读文档的情况下,我使用了Dispatchers.Main,我现在意识到这是针对android UI线程的。我可以使用一个调度程序来使协程在主线程上运行吗?如果没有,我将如何制作一个?

我环顾了kotlin文档,了解如何基于单个线程创建调度程序,但是除了newSingleThreadContext可以创建新线程之外,我什么都找不到。我还发现可以从Java执行器创建一个调度程序,但是我仍然不确定如何将其限制为一个已经存在的线程。

class AbstractNetworkComponent : CoroutineScope {
    private val packetProcessor = PacketProcessor()
    private val job = Job()
    override val coroutineContext = job + Dispatchers.IO
}

class PacketProcessor : CoroutineScope {

    private val job = Job()
    override val coroutineContext = job + Dispatchers.Main //Android only!
    private val packetHandlers = mutableMapOf<Opcode, PacketHandlerFunc>()

    fun handlePacket(opcode: Opcode, packet: ReceivablePacket, networker: Writable) {
        launch(coroutineContext) {
            packetHandlers[opcode]?.invoke(packet, networker)
        }
    }
}

因此,由于缺少Android组件,因此使用Dispatchers.Main会收到IllegalStateException。有没有一种方法可以创建一个分派器,该分派器会阻塞主线程直到其完成(就像runBlocking一样?)谢谢!

2 个答案:

答案 0 :(得分:0)

根据Guide to UI programming with coroutines kotlinx.coroutines ,有三个模块为不同的UI应用程序库提供协程上下文:

此外,还可以通过Dispatchers.Main kotlinx-coroutines-core 获得UI调度程序,并且ServiceLoader API发现了相应的实现(Android,JavaFx或Swing)。例如,如果您正在编写JavaFx应用程序,则可以使用Dispatchers.MainDispachers.JavaFx扩展名,它将是同一对象。

答案 1 :(得分:0)

runBlocking正是您需要的。它创建一个调度程序并将其设置在协程环境中。您可以使用

访问调度程序
coroutineContext[ContinuationInterceptor] as CoroutineDispatcher

,然后可以将其传递给实现CoroutineScope的对象或您要对其进行任何其他处理的对象。这是一些示例代码:

import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO
import kotlin.coroutines.ContinuationInterceptor

fun main() {
    println("Top-level: current thread is ${Thread.currentThread().name}")
    runBlocking {
        val dispatcher = coroutineContext[ContinuationInterceptor]
                as CoroutineDispatcher
        ScopedObject(dispatcher).launchMe().join()
    }
}

class ScopedObject(dispatcher: CoroutineDispatcher) : CoroutineScope {
    override val coroutineContext = Job() + dispatcher

    fun launchMe() = launch {
        val result = withContext(IO) {
            "amazing"
        }
        println("Launched coroutine: " +
                "current thread is ${Thread.currentThread().name}, " +
                "result is $result")
    }
}

这将打印

Top-level: current thread is main
Launched coroutine: current thread is main, result is amazing