Trying to understand Timer - tick

enonod

Well-Known Member
Licensed User
Longtime User
I have moved on from having a loop to using timer.
The program runs as a continuous loop, calculating, drawing, invalidating then displaying. Repeat ad infinitum.
Using timer tick I must specify a time. I cannot predict how long a cycle will take and it will probably vary.
It works but it works whatever time I specify!

Can I forget a timer and just have a loop that runs forever or will I be unable to process screen touches etc.
I guess my problem is that I cannot mentally relate the time element to anything.

Any help please
 

NJDude

Expert
Licensed User
Longtime User
Not neccessarily a loop (as in For-Next or Do-While) but as a chain, let me explain.

Let's say you have 3 SUBs, Calculate, Draw, Update, all those routines will take some time to process whatever they do, so, it can take more time or less time depending on the data, so, you should proceed to the next one when one finishes, like this:

B4X:
Sub Calculate

    Sum = Sum + SomeValue

    Draw 'Call this routine when Calculate is done

End Sub


Sub Draw

    Plot(X,45) 'I know is fake but...you get my point

    Update 'Call this routine when Draw is done

End Sub


Sub Update

    Open something, update, process

    Calculate 'Restart the process

End Sub

This way the Draw sub won't run until Calculate finishes and so on, you will be able to touch the screen, scroll ListViews etc, no problem.

I hope I was clear enough.
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
Thank you very much for that and it was perfectly clear.
I did not feel comfortable with the timer.
Hopefully if some of the subs are long (in time) this will not impact on the touch not being detected for a long time?
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
Many thanks, all solved
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
I thought this worked but it 'seems' that there may be a stack problem??
If we assume that the Update Sub does not contain the call to Calculate...
then the Update Sub would complete and then drop out of the Draw Sub and eventually drop out of the Calculate Sub to complete a cycle.

By re-calling Calculate before it has dropped out of End Sub, surely a recursion is taking place and will eventually crash.
My program using this technique crashed after 45 cycles.
Since every cycle is the same I can see no other explanation.
Also one extra stage is the Activity_Create which must first call this chain by calling Calculate.

Any comments please?
 
Upvote 0

NJDude

Expert
Licensed User
Longtime User
It will be hard to give a definite answer since something like this will depend on the nature of the code, you will have to make sure that the starting routine finishes successfully in order to continue and so on and so forth, any recursive action will have to be considered as well, in my experience, just a little bit of planning does the trick, however, if it doesn't work, then a different method should be used.
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
I am sure that the method quoted will always result in recursion.
I agree some other method will be required.

The only alternative solution I can see with the Subs you gave as an example would be to remove the calls to each next sub and call each sub in turn from outside, but I have picked up that it is undesirable and a timer should be used.
i.e.
In which case a loop is required to go back to the start.
Sub StartupSub
While True
Calculate
Draw
Update
End
End Sub
I therefore return to my original question, how to 'synchronise' a timer in the above example so that it runs out at the correct time and also allows screen touches to be immediately detected. If that is a stupid question please point me to an explanation of how such a system should work.
Many thanks.
 
Upvote 0

NJDude

Expert
Licensed User
Longtime User
There's no way to sync a timer since the time to complete a task or tasks is irregular, therefore, a solution like the one I sketched should be used, I would suggest you analyze your logic and determine how can you control the flow, there's no other way from where I stand.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
This suggestion recurses and so is bound to fail. A Timer would be a better solution. If the code does happen to run for longer than the timer interval there is no problem, the start of the next Timer interval will just be delayed. This would also allow the full UI message processing to occur which will not happen when only DoEvents is called which can also lead to problems.
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
I am sure that the method quoted will always result in recursion.
Before the processor enters another sub it will store all local variables to the stack, so that it can reload them when it exits the sub. This looks like infinite recursion. I dont think it is suitable for your problem.
You might as well use a Do...Loop with DoEvents instead.


How variable is the duration of your subs? I do not see any issue with using timers, why do you think you need to synchronise it to time out?

With a timer, you just add your 3 subs in there.

In order to set the Timer.Interval, you need to make sure the interval is large enough to do all the work you want it to. So it should be the worst-case duration of your subs.
In the case that the timer is unable to complete the work in that duration, I think the Timer_Tick message will get queued up, so it will happen after the last one is completed. Therefore your process will run as fast as possible without losing responsiveness.

EDIT: Just saw agrahams reply, which is thankfully consistent with mine
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
Thank you both for your confirmation of recursion but mostly the reassurance that the timer approach is not an issue.
I had assumed that the timer period had to timeout after a complete cycle but not before and that if the period were too long the code would wait for a retrigger and thus slow the cycle down.
I could not see how to measure the time taken (max) for my subs.

Any additional info would be appreciated but generally my mind is at ease.
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
I could not see how to measure the time taken (max) for my subs.
This depends on what you are trying to do, and how.
Simplest way would be to Log the time before and after an operation, and the difference is the time taken for your code to run. Do it a couple of times in different circumstances and different parameters to play around.
But I do not think you really need to do it unless you are doing something really complex. (If it runs fast enough on the emulator it should run on any device!)
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
Thank you very much. I have now run the code with timer set to 10 and 100ms and it works OK.
 
Upvote 0

dagnabitboy

Active Member
Licensed User
Longtime User
Why not use a flag to tell your timer routine if your calculation code is done? Like this:
B4X:
Sub Process_Globals
   Dim timer1 As Timer
   timer1.Interval(10)
End Sub

Sub Globals
   Dim processFinished As Boolean      
End Sub

Sub Activity_Create(FirstTime As Boolean)
   processFinished=True ' set true first time so it will run
   timer1.enabled=True
End Sub

Sub timer1_tick
   If processFinished=True
      processFinished=False
      runMyCode
   End If
End Sub
Sub runMyCode
   your calculation
   ...
   processFinished=True
End Sub
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
An interesting suggestion which I will look at thank you.
I will say though, the program is running 'apparently' the same and at the same speed whatever timer value I use.
 
Upvote 0

enonod

Well-Known Member
Licensed User
Longtime User
Understood and it makes it clear, as you said in an earlier post, and that is why it runs 'regardless' of timer setting.
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…