Estoy configurando un marco de trabajo de red basado en kotlin coroutine para jvm. Las clases Cliente y Servidor implementan CoroutineScope, y la anulación de coroutinecontext es Dispatchers.IO, ya que estoy bastante seguro de que es el Dispatcher correcto para usar en tal caso. Sin embargo, deseo manejar paquetes de lectura en el hilo principal, o al menos proporcionar esa opción. Sin leer la documentación, utilicé Dispatchers.Main, que ahora me doy cuenta de que es para el subproceso de interfaz de usuario de Android. ¿Hay un despachador que pueda usar para ejecutar una corrutina en el hilo principal? Si no, ¿cómo haría para hacer uno?
Revisé la documentación de Kotlin sobre cómo crear un despachador basado en un solo hilo, pero no pude encontrar nada además de newSingleThreadContext que crea un nuevo hilo. También descubrí que es posible crear un despachador desde un Ejecutor de Java, pero todavía no estoy seguro de cómo limitar esto a un hilo ya existente.
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) } } }Entonces, con Dispatchers.Main obtengo una IllegalStateException debido a que falta el componente de Android. ¿Hay alguna manera de crear un despachador que bloquee el hilo principal hasta que se complete (como lo hace runBlocking?) ¡Gracias!
Según la Guía para la programación de UI con coroutines, kotlinx.coroutines tiene tres módulos que brindan contexto de coroutine para diferentes bibliotecas de aplicaciones de UI:
Además, el despachador de interfaz de usuario está disponible a través de Dispatchers.Main de kotlinx-coroutines-core y la implementación correspondiente (Android, JavaFx o Swing) es descubierta por ServiceLoader API. Por ejemplo, si está escribiendo una aplicación JavaFx, puede usar la extensión Dispatchers.Main o Dispachers.JavaFx , será el mismo objeto.
runBlocking es exactamente lo que necesita. Crea un despachador y lo establece en el contexto coroutine. Puede acceder al despachador con
coroutineContext[ContinuationInterceptor] as CoroutineDispatcher y luego puede pasarlo a un objeto que implemente CoroutineScope o cualquier otra cosa que desee hacer con él. Aquí hay un código de muestra:
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") } }Esto se imprimirá
Top-level: current thread is main Launched coroutine: current thread is main, result is amazing