0

I have a situation where I want to update an Activity's text fields as data comes in. The update only occurs when the simulation is completed, not while it is running (takes maybe 2 seconds to run).

Here is the code I have:

    ...
    private var totalLoops = 0
    private val updateDisplayTask = Runnable {
    totalLoopsTV.text = totalLoops.toString()
    totalEmailsSentTV.text = totalEmailsSent.toString()
    totalPushesSentTV.text = totalPushesSent.toString()

    private fun mainLoopFunction(currentTime: Long) {
    ...
      totalLoops++

      if(totalLoops % 20 == 0 || onDeckList.size == 0) {
          Timber.w("UPDATING UI")
          runOnUiThread(updateDisplayTask)
          //handler.post(updateDisplayTask)
      }
    } //end of main loop
     

I've tried both runOnUiThread and handler/post as well as a few other things using Kotlin Coroutines, but nothing so far has worked. Can you see what I'm doing wrong here please? I see the logs of UPDATING UI so I know that the updates do get sent and I do see the last update (the only one I see) at the end.

user443654
  • 821
  • 1
  • 7
  • 21
  • It's not clear what you're attempting to do. Maybe you're trying to update your ui at a fixed rate with the current time? – Nicola Gallazzi Nov 30 '20 at 17:13
  • The time there is just used inside of the simulation loop to make a calculation and it doesn't impact the times the UI is to get updated. What drives the UI to update or not is the % of 20. Looking at the logs, the update should happen several times but only happens at the very end. – user443654 Nov 30 '20 at 17:41
  • It seems the totalLoops value changed so quickly in a short time, that why you can see a lot of "UPDATING UI" in the log cat, but only the last update is showed on UI. – Son Truong Dec 01 '20 at 02:31
  • 1
    Looks like `mainLoopFunction` is running on the main thread. All the `Runnable`s submitted by `runOnUiThread` cannot run before `mainLoopFunction` returns. – George Leung Dec 01 '20 at 08:57
  • It is all on the main thread, but each loop finishes up in less than 1/10th of a second but the UI does not update until the end. – user443654 Dec 07 '20 at 21:04

1 Answers1

0

Is this running on another thread, and then you run updateDisplayTask on the main thread? If you're updating totalLoops, totalEmailsSent and totalPushesSent on one thread (this worker thread) and reading them on another (main thread) then because of the way concurrency works, you might not actually see the new values on the main thread.

There are a few ways to manage synchronizing them, but if you're only writing the values on one thread (and you're not massively concerned about the possibility of some of the values changing partway through reading them, so they don't all match up) you can just use the @Volatile annotation on those variables to make them update across threads (works like the volatile keyword in Java).

If you care about atomic updates (everything changing together, can't read or write while something is in the middle of reading or writing them) you'll have to look into some kind of locking, like using synchronized methods and blocks. It's kind of a major (important!) subject, here's a post on it: https://proandroiddev.com/synchronization-and-thread-safety-techniques-in-java-and-kotlin-f63506370e6d

cactustictacs
  • 17,935
  • 2
  • 14
  • 25
  • It's all in the same Activity...all on the same thread. – user443654 Dec 07 '20 at 21:03
  • In that case why are you using ``runOnUiThread``? That posts a runnable task to the main thread's message queue, and it won't get to those until it's finished what it's doing, which includes running that loop to completion. So all your updates will happen after ``mainLoopFunction`` has completely finished, grabbing the current values to display (which will be the final values when the updates actually get run). If this **is** all on the main thread (which you shouldn't be blocking for 2+ seconds anyway!) just run ``updateDisplayTask`` directly in your loop – cactustictacs Dec 07 '20 at 23:44