Click here to Skip to main content
15,887,860 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have an app using Rad Studio c++ 10.2.
My problem is to have a sequence of :SetupDelay ->ExerciseDelay->Rest Delay
before moving to the next exercise.
The UI presents the current exercise attributes and Must wait for each of these delays sequentially before continuing to the next.
I have the following code using a TTimer which works on Windows, but when I compile for Android it causes the UI to crash.

I am looking for a portable method which supports all platforms (Win,OSX,IOS,Android) supported by Rad Studio. Below is the code that I first used for windows:


While the delay is happening there are several buttons that need to be serviced in case of Skip,Pause,Cancel so that the user is not locked in during the delay phase.


My process is: (Sequential process in UI)

1: Display current exercise attributes

2: Delay for Setup - Countdown timer updates label each second

3: Delay for Exercise Time - Countdown timer updates label each second

4: Delay for Rest time - Countdown timer updates label each second

5; Update set counter and loop (3-4) until all sets for current exercise are completed

While inside the delay the UI must be active so that all the buttons (Next,Pause,Cancel) respond quickly.

To clarify: The code written for Rad Studio is multi-device so the same code compiled/run for Windows fails on Android. The failure on Android is as follows:
When the timer first runs the Android app freezes and none of the timers run. If I click any of the buttons, the app crashes. If I do nothing the app just sits there and does nothing.

What I wanted to do is run the delay within a thread but there is no way I can see to wait for that thread to finish from the main UI thread without blocking, which is basically the same problem I have without the threaded approach.

Any help or idea would be appreciated.

What I have tried:

Below is my existing code working for Windows.


I tried using a separate thread for the delay, but the issue is still the UI waiting for the delay to finish involves constantly checking the delay status which effectively halts the UI. As far as I can determine Android does not support ProcessMessages so any solution should not use this method.

void __fastcall	TTabbedwithNavigationForm::DoDelay( int delay )
{
int	pdl;
char	buf[ 256 ];

    NEXT = false;
    CANCEL = false;

    DelayCounter = delay;
    Timer1 ->Enabled = true;

// we use this loop so that ProcessMessages and Label updates are not called too often. Without this there is a noticeable lag in response.
    pdl = 5000;

    while ( DelayCounter > 0 )
    {
	if ( --pdl == 0 )
	{
	    sprintf( buf, "%3d", DelayCounter );
	    LBL_RestExerciseTime ->Text = buf;

	    Application ->ProcessMessages();

	    pdl = 5000;
	}
	else
	{
	}

	if ( CANCEL == true )
	    break;

	if ( NEXT == true )
	    break;
    }

    Timer1 ->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TTabbedwithNavigationForm::Timer1Timer(TObject *Sender)
{
    if ( DelayCounter > 0 )
    {
	--DelayCounter;

	if ( STOP == true || CANCEL == true )
	{
	    Timer1 ->Enabled = false;
	    DelayCounter = 0;
	}

	if ( DelayCounter == 0 )
	{
	    Timer1 ->Enabled = false;
	}
    }
}
Posted
Updated 11-Aug-19 10:28am
v2
Comments
Richard MacCutchan 25-Jul-19 11:10am    
You need to show us the Android code and explain exactly where the crash occurs.
Rick York 25-Jul-19 15:56pm    
I don't have a direct solution to your problem but if I were you, I would implement a state machine for this. It doesn't have to be a general purpose if you want to be quick about it. The reason is you can easily transition between states, you won't have a bunch of flags all over the place, and you can maintain the update timer. The state would determine when buttons are enabled and disabled. Often a few flags are adequate for this kind of thing but when you throw in enough curve balls it needs to be taken a bit farther and I think an SM would be the right way to go for you.

Why do you have "delays" when you're using "timers"?

If your refresh rate is once per second, then your "interval" s/b 1 second.

You can put all your "tasks" in a queue and pop one at the end of every x intervals (for example).

The UI stays responsive while the timer waits to fire (and you're not "delaying").

If you're "busy" in an interval, disable the timer and resume when appropriate to avoid reentrancy issues.
 
Share this answer
 
Comments
Member 10250894 26-Jul-19 6:00am    
My timer has a 1 sec resolution but since the user can ask for any length it is required that I wait until that requested delay. If I start the timer and wait even 1 second for it to timeout the entire sequence would have completed. The "Delay" here is the time the user needs to do an exercise period, a rest period or to prepare for another exercise. Maybe delay is a bad moniker for that. The issue for me is to actually wait for each of these phases of an exercise cycle while still being able to display the countdown time and the elapsed time and still being responsive to button clicks. Dang Android !!! I wonder what surprises I will encounter when I try to run this on IoS???
I tried using a separate thread for the delay, but the issue is still the UI waiting for the delay to finish involves constantly checking the delay status which effectively halts the UI.
No, that is exactly the problem: you may not constantly check within your own function, you have to move that check to the event queue instead - then you don't even need to care about creating a separate thread! See Timer Event Operations - Windows applications | Microsoft Docs[^]

Basically, when the timer (delay) starts, you tell the timer to send an event n seconds from now, and then you need to provide the event handler function that is called when the event triggers.

I won't be able to be more specific - it's been decades since I've last programmed UI stuff, and I understand things have moved since then. But timers still exist, as well as events.
 
Share this answer
 
After trying all permutations of serial delays and threading (and ProcessMessages ) I have concluded that a state machine was indeed the correct solution here.

I ended up using 2 timers, 1 to drive the state machine, and a second timer used by the state machine to time the actual delays needed within the exercise sequences.

The code runs successfully on both windows and android. I don't have an apple developer ID yet (I understand you have to pay in order to side-load apps on an apple device.) but I see no reason this solution wont run there either.

I appreciate all the responses.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900