10.4. Actors

Actors are executed throughout the lifetime of the application. These actors typically need non-blocking communication mechanisms with other threads. This is accomplished using channels.

Actors and Channels. Actors and Channels.
Source: Javier Salvador (Original image) License: CC BY-NC-ND 4.0

Kotlin’s couroutine library provided a mechanism for creating actors but was marked as deprecated by Google. In this documentation we present you with a simple alternative to implementing Actors.

We can model an Actor or subsystem with a class that has this structure:

class MySubsystem {
   val channel = Channel<String>()

   public fun sendMessage(msg:String)
   {
       GlobalScope.launch(Dispatchers.Main) {
           channel.send(msg)
       }
   }

   public fun start()
   {
       GlobalScope.launch(Dispatchers.Default) {
           while(isActive){
               val msg = channel.receive()

               if(msg=="quit") {
                   cancel()
               }
               else if(msg=="log") {
                   Log.i("Susbsystem!",thread.currentthread().name.toString())
               }

           }
       }
   }
}

The class has a Start method that runs an infinite loop within the coroutine while the coroutine is active and is permanently running the channel.receive() method.

This method locks the thread until a message is received. Depending on the message received, it runs one piece of code or another: if it receives the “log” message, it writes the message in the Log window; on the other hand, if it receives the “quit” message, the subsystem stops because the coroutine is no longer Active.

In this example, we use a string channel. However, we can also use channels for message types defined by us, which can require more complex data structures.

There is also a send method that can be used by any thread to queue messages that should be processed by the subsystem.