B4A Class [B4X][B4XLib] WaitForWithTimeout --> TimeoutHandler

I have read many times the request for a "Wait For" with the addition of a timeout.

This class is an attempt to implement that functionality.

It is a B4X class, in the sense that it can be used with B4A, B4J and B4i; after all it uses only one B4XView which is completely optional and almost never necessary.

I don't list the methods and properties here; each of them has its own description in the source (even if they are not very "studied" descriptions).

The class is in the attached example project, of course (it's not a smart/beautiful example :D)


[I would like Erel to look at and improve it]




Wrong place, the project attached is a B4J project! Sorry.

Attached the B4XLib (V. 1.11)

TimeoutHandler attached (see post #9)

TimeoutHandler V. 1.1
- Just added the description of the method with example code (useful, copy & paste)
 

Attachments

  • WaitForWithTimeoutTest.zip
    4 KB · Views: 486
  • B4J TimeoutHandler.zip
    3.2 KB · Views: 322
  • B4J TimeoutHandler 1_1.zip
    3.5 KB · Views: 368
  • B4XTimeoutHandler.b4xlib
    948 bytes · Views: 272
Last edited:

AnandGupta

Expert
Licensed User
Longtime User
Hey, I also didn't "like" it (just did now) :)
Maybe he is busy, remember he is on Vacation.

Regards,

Anand
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Maybe he is busy, remember he is on Vacation.
Not any more...
Erel does not like this, ok but... why?
In most cases it is a mistake to create a layer above Sleep or Wait For. It makes things more complicated, it might add subtle bugs and it is unlikely to fit many use cases.

I prefer to create timeouts with this approach:
B4X:
Sub btnStart_Click
   btnStart.Visible = False
   lblCountdown.Visible = True
   lblExecuted.Text = ""
   btnCall.Visible = True
   '**************
   Dim cancel(1) As Boolean
   TimeoutImpl(cancel, 3, "CardPlayed")
   Wait For CardPlayed
   If cancel(0) = True Then
       lblExecuted.Text = "too slow"
   Else
       cancel(0) = True
       lblExecuted.Text = "Played: " & tfCartaGiocata.Text
   End If
   '*************
   btnStart.Visible = True
   btnCall.Visible = False
   lblCountdown.Visible = False
End Sub

Sub TimeoutImpl(Cancel() As Boolean, Duration As Int, EventName As String)
   Do While Duration > 0
       lblCountdown.Text = Duration
       Sleep(1000)
       If Cancel(0) Then Return
       Duration = Duration - 1
   Loop
   Cancel(0) = True
   CallSubDelayed(Me, EventName)
End Sub

Sub btnCall_Click
   CallSubDelayed(Me, "CardPlayed")
End Sub

By passing a single element array to TimeoutImpl we can control its behavior from the calling method.
Note that TimeoutImpl can be used multiple times as long as the event names are different.
 

LucaMs

Expert
Licensed User
Longtime User
Unfortunately I am very far from having a logical capacity as yours (I hope that the reason is only the fact that your logic is excellent and not also because mine is scarce, but I fear that the second hypothesis is also correct :D:(). For example, just by looking at my code you can already foresee possible bugs, I can't go that far (you're probably a good chess player).

Also, I have to spend a few minutes figuring out the big difference between the two sources, so much so that I still don't see the real advantages, which I am sure are there, and I didn't understand why to use a Boolean type array instead of a single variable.

I will read your code again (and your comments) and I'll let you know if I can figure it out :)

When I will have understood the code correctly, however, I will almost certainly want to implement it in a class since this generally makes things a lot easier, even the readability of the code itself.
 

LucaMs

Expert
Licensed User
Longtime User
Instead of...
I will read your code again (and your comments) and I'll let you know if I can figure it out
...thinking too much, I wanted first try your code writing TimeoutImpl in a code module (b4j is the best for tests :)).

Just added two parameters (you know why):
B4X:
Public Sub TimeoutImpl(Callback As Object, EventName As String, Cancel() As Boolean, Duration As Int, lblCountdown As Label)
   Do While Duration > 0
       If lblCountdown.IsInitialized Then
           lblCountdown.Text = Duration
       End If
       Sleep(1000)
       If Cancel(0) Then Return
       Duration = Duration - 1
   Loop
   Cancel(0) = True
   CallSubDelayed(Callback, EventName)
End Sub

um... I should add another parameter, the "step" - here fixed to 1000.

Only after tried this "change" I realized that using your code I could not have the possibility of passing a parameter - in the example, pressing the btnCall key simulates a data received remotely (a card code played by a client app), data which should be received by the event itself (bad explanation, sorry, but you understand all anyway :D)
 

LucaMs

Expert
Licensed User
Longtime User
I liked and used the code written by Erel (slightly modified, added a couple of parameters and the reception of the data in the "waited" event).

The trouble is that now this thread is slightly confusing (as is its author, after all :D). Besides, I should have written it in the B4J forum.

I'm attaching the new project to the first post of this thread, containing the new class based on Erel's code. Very simple class, it has only one public method, which could also be used very well in a code module instead of in the class.

[I suppose that a small change is needed to use it with B4i, but since I don't have B4i...!]
 
Last edited:
Top