I have a view, and i have a tcp connection. i want...
# tornadofx
l
I have a view, and i have a tcp connection. i want to update the view when receiving data from the connection but without the view ever becoming unresponsive. i thought all i need to do is use a separate thread for the networking stuff, if i try to update the view (specically, adding an element to an observable list) i get an
IllegalStateException: Not on FX application thread
. How do I deal with this? also why does it only happen when the list isn't empty ?
m
Did you use the
ui
block together with
runAsync
? Any view update must be done inside the UI thread, it seems like you're trying to update UI elements outside of it. Please refer to https://edvin.gitbooks.io/tornadofx-guide/part1/3.%20Components.html, chapter "Long running tasks".
l
whenever i read about long running tasks it is always assumed that i only have tasks that finish eventually. however in my case i have a task that basically never finishes. the network thread spins endlessly in a while loop reading one message from the connection after another and adds them to the ui (thats where the exception is thrown) until the client disconnects. it seems my whole approach is wrong, but i just cant figure out how else im supposed to do it. I'll need an example
consider the following code:
Copy code
import <http://tornadofx.App|tornadofx.App>
import kotlin.concurrent.thread

fun main() {
   launch<MyApp>()
}

class MyApp : App(MyView::class)

class MyView : View("MyTestProgram") {
   val myList = observableListOf("banana", "potato")

   override val root = form {
      listview(myList)
      
      thread {
         runBlocking {
            MyNetworker.readMessages(myList)
         }
      }
   }
}

object MyNetworker {
   private lateinit var socket: Socket
   //lets assume we already have an established tcp connection to keep the example short

   suspend fun readMessages(myList: ObservableList<String>) {
      val readChannel = socket.openReadChannel()

      while (true) {
         val message = readChannel.readUTF8Line(32)!!
         myList.add(message) //exception is thrown here because we're using another thread to modify the ui
      }
   }
}
i know its garbage in many ways, but it shows what i want to do. what would be the proper way to do it?
a
Wrap the "myList.add()" function call inside a "runLater{}" block, this should do the trick :)
l
that seems to work, but i still feel like my whole approach is wrong since im forcing an asynchronous networking library to run synchronously
a
Oh yeah, you definitely should also wrap the blocking call to "readChannel. ReadUTF8Line()" inside a "runAsync{}" block, as @matthjes suggested
l
ReadUTF8Line() is a suspending call, not a blocking call. also wrapping just that line in runAsync makes so sense since the following code depends on it