Need help with VR, TTS, and timer please

DTsEMT

Member
Licensed User
Longtime User
I've run into a strange problem, I hope someone has an answer!

The code is rather lengthy, so please forgive my use of pseudo code.

Presume all standard modules which all work just fine - VR1, TTS1, Timer_Tick, S1 to return bFinished from PhoneEvents, etc.

If I perform this:

Sub Globals
Dim Asking as Boolean=False
<dim everything else, no errors>

Sub Say(ALine as String)
Timer.Enabled=True
TTS1.Speak(ALine,False)
End Sub
'
Sub Timer_Tick
If bfinished=TrueThen
<do a bunch of stuff>
If Asking Then VR1.Listen
End If
End Sub

Sub VR1_Result (Success as Boolean, Texts as List)
If Success=False Then Return
<do something with the texts>
Dim YourResponse As String=Texts.Get(0)

The following code works just fine:

Sub Foo
Asking=True
Say("Something or another")
<your response is returned correctly as a string>
End Sub

Tracing everything in the log, I see subroutine SAY enable the timer; I see the timer fire until bfinished=True, I see the proper code returned.

The problem is this:

Sub Wow
For i=0 to 10
Say("The value for i is " & i)
Asking=True
Say("Say something")
<if your response = x then y>
Next
End Sub

In this case, the log shows 10 "The value for i is" messages, the timer never fires, and the responses are all evaluated as if they returned null.

It's as though the code is more concerned with the for/next loop than the timer firing and conditionally ending.

I've tried putting in Do While loops in Sub Wow to give the timer time to fire (it's initialized at 500ms) but the for/next loop ignores the timer entirely.

Anyone else run into this, or am I doing something completely wrong?

Thanks!

:sign0085:
 

agraham

Expert
Licensed User
Longtime User
This is the way that event driven programming works. All modern GUIs work like this. A program responds to events generated by users or the operating system. Events are delivered as messages to a message queue and a message loop reads the messages and despatches them, that is it calls the program Sub or part of the operating system that is supposed to deal with the message.

After despatching an event to your program the message loop can only run again once your Sub has returned to it. So by looping in your Sub the message loop never gets to run so the Timer events can never run. You need to structure your program so that it doesn't loop endlessly in a Sub, in fact if it does for more than a few seconds Android will kill your application.

The reason modern GUIs work like this is because everything that is concerned with manipulating the user interface run on a single thread which vastly simplifies both the OS and application programs as it is certain that only one routine at any one time can touch the GUI. In fact it is considered an error for another thread to try to do so and usually this will be detected and an exception will be thrown if this is attempted.

The DoEvents keyboard can be used in a loop and what this does is pump the message queue and despatch waiting events. However only events that update the user interface will actually run, others are merely re-queued so you should use it only where you need the display to be updated and in a properly structured program this should be necessary only very occasionally if ever.

As a point of interest, this is how modal dialogs work. Instead of returning to the message loop a modal dialog pumps the message queue itself. This is how it can see the events for the buttons that dismiss the dialog.
 
Upvote 0

DTsEMT

Member
Licensed User
Longtime User
Thanks!

Thank you for the response!

I sometimes fall back into the 1970's programming mode where events are linear. Thanks for the wakeup.

I was able to work around this issue by creating a separate timer, and processing the return from the timer event.
 
Upvote 0
Top