Android Question Can I have a short non-blocking delay in a service?

pjetson

Member
Licensed User
Longtime User
I am testing various ways of doing something at the moment, and I need to have a sub called from within a service wait for about a second before it returns. Doing a
B4X:
sleep(1000)
in the sub seems to produce strange results; possibly that's due to the side effects of resumable subs. I also tried a simple
B4X:
For i = 1 To 1000000: Next
loop, but that just seems to block everything, and log messages that should have appeared before the loop don't appear until after it.

Is there any way to create a non-blocking delay of about a second inside a service? Or is there something I can call that would take about a (non-blocking) second to return?

Thanks, Peter
 

pjetson

Member
Licensed User
Longtime User
I don't want to block the main thread, but in my test code, I want to simulate the time that a task would normally take, without performing that actual task. The task in the real program calls httpjob, so it's non-blocking, but I can't put the real call into this test code.

I have tried this code. In the Sending sub, I want to have a one-second delay where the call to FirstSub is.
B4X:
Sub Sending
   LogColor("Transfer.Sending start", Colors.Red)
   Private item As String
   If Main.FIFO.Size > 0 Then
     item = Main.FIFO.Get(0)
     Log("Sending item " & item)
     FirstSub
     Main.FIFO.RemoveAt(0)
   End If
   LogColor("Transfer.Sending end", Colors.Red)
End Sub

Sub FirstSub
   Log("FirstSub started")
   SecondSub
   Wait For SecondSub_Complete
   Log("FirstSub completed")
End Sub

Sub SecondSub
   Log("SecondSub started")
   Sleep(1000)
   Log("SecondSub completed")
   CallSubDelayed(Me, "SecondSub_Complete")
End Sub

But this is the result from the log screen:
Transfer.Sending start
Sending item 1503038258830
FirstSub started
SecondSub started
Transfer.Sending end

The Sending sub returns before SecondSub and FirstSub returns, so there is no delay.

Peter
 
Upvote 0

pjetson

Member
Licensed User
Longtime User
I've tried to work this out, but it seems that I must be expecting something that isn't possible.

I wrote this test code (with B4A V7.30):
B4X:
Sub Activity_Resume
   Private i As Int
   For i = 1 To 5
     Log("Iteration " & i)
     Sub1(i)
   Next
   Log("Done")
End Sub

Sub Sub1(i As Int)
   Log("Sub1 " & i & " start")
   Wait For (Sub2(i)) Complete (Result As Boolean)
   Log("Sub1 " & i & " finish")
End Sub

Sub Sub2 (i As Int) As ResumableSub
   Log("Sub2 " & i & " start")
   Sleep(3000)
   Log("Sub2 " & i & " finish")
   Return True
End Sub
The log screen shows this:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Iteration 1
Sub1 1 start
Sub2 1 start
Iteration 2
Sub1 2 start
Sub2 2 start
Iteration 3
Sub1 3 start
Sub2 3 start
Iteration 4
Sub1 4 start
Sub2 4 start
Iteration 5
Sub1 5 start
Sub2 5 start
Done
Then, after three seconds, it shows this:
Sub2 1 finish
Sub2 2 finish
Sub1 1 finish
Sub2 3 finish
Sub2 4 finish
Sub1 2 finish
Sub2 5 finish
Sub1 3 finish
Sub1 4 finish
Sub1 5 finish
What I was expecting (or rather hoping for) was something more like this:
Interation 1
Sub1 1 start
Sub2 1 start
(a three second delay here)
Sub2 1 finish
Sub1 1 finish
(and so on, four more times)
Is there any way I can implement a one second delay in my code, for testing purposes only, that doesn't block anything, but also doesn't return/stop until the delay is finished?

Regards,
Peter
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Is there any way I can implement a one second delay in my code, for testing purposes only, that doesn't block anything, but also doesn't return/stop until the delay is finished?
Again. The answer is in post #2

Use the wait for solution.
 
Upvote 0

pjetson

Member
Licensed User
Longtime User
Again. The answer is in post #2
Thanks, Manfred. As far as I can see, my code in post #7 here does use the Wait For solution as it is used in the link Erel posted.

In post #2 above, Erel said:
You should use Sleep (which does not block). If you want to call this sub and wait for it to complete
However, I now realise that in the first post of the link Erel posted, it says:
Remember that a call to Sleep or Wait For in a resumable sub causes the code flow to return to the parent
That is exactly what seems to happen when I use the suggested Wait For solution. Perhaps I'm just being slow here - is the answer to my original question "No"?

Peter
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Sub1 is a resumable sub.
You should use Wait For to wait for Sub1 to complete:

B4X:
Sub Activity_Resume
   Private i As Int
   For i = 1 To 5
     Log("Iteration " & i)
     Wait For (Sub1(i)) Complete (Result As String)
   Next
   Log("Done")
End Sub

Sub Sub1(i As Int) As ResumableSub
   Log("Sub1 " & i & " start")
   Wait For (Sub2(i)) Complete (Result As Boolean)
   Log("Sub1 " & i & " finish")
   Return ""
End Sub

Sub Sub2 (i As Int) As ResumableSub
   Log("Sub2 " & i & " start")
   Sleep(3000)
   Log("Sub2 " & i & " finish")
   Return True
End Sub
 
Upvote 0

pjetson

Member
Licensed User
Longtime User
Thank you, Erel (and Manfred). I was misunderstanding the code in the link you posted - now it's obvious where I was going wrong and the final solution makes sense even to me. There was no need for two subs, and the Wait For had to be in the original calling sub. My apologies.

The final (simple!) code is:
B4X:
Sub Activity_Resume
    Private i As Int
    For i = 1 To 5
        Log("Iteration " & i)
        Wait For (Sub1(i)) Complete (Result As Boolean)
    Next
    Log("Done")
End Sub

Sub Sub1 (i As Int) As ResumableSub
    Log("Sub1 " & i & " start")
    Sleep(3000)
    Log("Sub1 " & i & " finish")
    Return True
End Sub
Regards, and thanks for putting up with my silly questions, Peter
 
Last edited:
Upvote 0
Top