Android Tutorial [B4X] Resumable subs that return values (ResumableSub)

Erel

Administrator
Staff member
Licensed User
Remember that that a call to Sleep or Wait For in a resumable sub causes the code flow to return to the parent.

Example:
B4X:
Sub Button1_Click
Sum(1, 2)
Log("after sum")
End Sub

Sub Sum(a As Int, b As Int)
Sleep(100) 'this will cause the code flow to return to the parent
Log(a + b)
End Sub
Output:
after sum
3
This is the reason why it is not possible to simply return a value.

Solution

Resumable subs can return a new type named ResumableSub. Other subs can use this value to wait for the sub to complete and get the desired return value.
B4X:
Sub Button1_Click
   Wait For(Sum(1, 2)) Complete (Result As Int)
   Log("result: " & Result)
   Log("after sum")
End Sub

Sub Sum(a As Int, b As Int) As ResumableSub
   Sleep(100)
   Log(a + b)
   Return a + b
End Sub
Output:
3
result: 3
after sum
The above Button1_Click code is equivalent to:
B4X:
Sub Button1_Click
   Dim rs As ResumableSub = Sum(1, 2)
   Wait For(rs) Complete (Result As Int)
   Log("result: " & Result)
   Log("after sum")
End Sub
The steps required are:

1. Add As ResumableSub to the resumable sub signature.
2. Call Return with the value you like to return.
3. In the calling sub, call the resumable sub with Wait For (<sub here>) Complete (Result As <matching type>)

Notes & Tips

- If you don't need to return a value but still want to wait for the resumable sub to complete then return Null from the resumable sub and set the type in the calling sub to Object.
- Multiple subs can safely call the resumable sub. The complete event will reach the correct parent.
- You can wait for resumable subs in other modules (in B4A it is relevant for classes only).
- The Result parameter name can be changed.
 
Last edited:

jahswani

Well-Known Member
Licensed User
Starting from B4A v7.30, B4J Vx.xx and B4i Vx.xx it is possible to return values from resumable subs.

Remember that that a call to Sleep or Wait For in a resumable sub causes the code flow to return to the parent.

Example:
This Was One Of My Wishes You said Never And less than 3 Months You found a way to implement it. Who's finally the boss here ?
 
Last edited:

tucano2000

Active Member
Licensed User
Thanks Erel for the improvements !!! Good Work.


I think I missed translating the text. When you hover over the button. Like this one in beta, I saw this little detail.

Edit: When you close the application and all the internal windows the same occurs.
button.png
 

Erel

Administrator
Staff member
Licensed User
Who's finally the boss here ?
The customer is always right :)

I think I missed translating the text. When you hover over the button. Like this one in beta, I saw this little detail.
(This is not really the place for this discussion.) This phrase is currently not localizable.
 

johndb

Active Member
Licensed User
I thought resumable subs was a game changer but now with being able to return a value has taken it to the next level!
I removed all of my callback code and callsubs in my many resumable code routines and replaced it with this new feature. I haven't encountered any problems so far.
Thank you @Erel.
 

GuyBooth

Active Member
Licensed User
Starting from B4A v7.30, B4J Vx.xx and B4i Vx.xx it is possible to return values from resumable subs.
This is really useful, and I've been simplifying a lot of code. Now I find an example where I can't figure out the correct syntax. I have been calling this sub:

B4X:
''' Simple message requiring OK click to move on. Also called from the service
Public Sub Display_OKMessage(Callback As Object, Message As String)
    Msgbox2Async (Message,"Music Machine", "","OK","",TMM.gbmpLogo36x36, False)
    Wait For msgbox_result (iResult As Int)
    ' Call back
    CallSubDelayed(Callback,"OK_Confirmed")
End Sub
Within the same module, the calling code was (for example):
B4X:
        Display_OKMessage(Me, "The Local Collections Database does not exist & could not be created.")
Wait For OK_Confirmed
But I also called the code from a different module, like this:
B4X:
            CallSubDelayed3(TMM_Connections, "Display_OKMessage", Me, _
            $"Internal Server Error reported by HTTP Communication."$)
Wait For OK_Confirmed
The sub I now call looks like this:
B4X:
' Simple message requiring OK click to move on. Also called from the service
' Calling Syntax: Wait For(Display_OKMessageAsync(Message)) Complete (OKConfirmed as String)
Public Sub Display_OKMessageAsync(Message As String) As ResumableSub
    Msgbox2Async (Message,"Music Machine", "","OK","",TMM.gbmpLogo36x36, False)
    Wait For msgbox_result
    Return "OK"
End Sub
Which from within the same module I can call like this:
B4X:
Wait For(Display_OKMessageAsync("Click OK to Confirm")) Complete (OKConfirmed as String)
But how do I call it from a different module? Do I still CallSubDelayed - in which case how do I add the arguments?
 

Erel

Administrator
Staff member
Licensed User
When you say a different module, you mean that this code is in an activity and you call it from a service?

It will not work with CallSubDelayed as CallSubDelayed does not return a value. However you can use CallSub, assuming that the activity is currently visible.

B4X:
Wait For (CallSub2(TMM_Connections, "Display_OKMessageAsync", "Test")) Complete (Result As String)
 
Last edited:

GuyBooth

Active Member
Licensed User
When you say a different module, you mean that this code is in an activity and you call it from a service?

It will now work with CallSubDelayed as CallSubDelayed does not return a value. However you can use CallSub, assuming that the activity is currently visible.
That's the syntax I'm looking for.
BTW, to clarify - since this is a tutorial thread - I assume you meant "It will NOT work with CallSubDelayed".
 

ilan

Expert
Licensed User
hi, i have a question related to ResumeableSub

this is my code:

B4X:
Sub reloadAds
    Dim myappinfo As getappinfo
    myappinfo.Initialize(Me,"myappinfo","www.sagital.mysalarynew")
  
    Wait For myappinfo_Success Complete (obj As Object)
    LogColor("finish 2",Colors.Green)
End Sub

Sub myappinfo_Success(obj() As Object) As ResumableSub 'title, description, rating, price, link, installs, appicon
    LogColor("finish 1",Colors.Red)
    Dim l As List
    l.Initialize
  
    For i = 0 To obj.length - 1
        l.Add(obj(i))
    Next
    File.WriteList(File.DirInternal,"myad" & adPos & ".txt", l)
  
    Return obj
End Sub
but this is my log:

*** Service (starter) Create ***
24mode: 24
5
shabbat = false
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
salbrutt: 40.99
Panel size is unknown. Layout may not be loaded correctly.
Panel size is unknown. Layout may not be loaded correctly.
Panel size is unknown. Layout may not be loaded correctly.
ApproximateScreenSize: 4.589389937671455
** Activity (main) Resume **
*** Service (firebasemessaging) Create ***
** Service (firebasemessaging) Start **
*** Service (loadadmodule) Create ***
** Service (loadadmodule) Start **
Billing service connected.
Checking for in-app billing 3 support.
In-app billing version 3 supported for www.sagital.mysalarynew
Subscriptions AVAILABLE.
*** Service (httputils2service) Create ***
** Service (httputils2service) Start **
** Service (httputils2service) Start **
finish 2 '<<<<<<<<<<<
finish 1 '<<<<<<<<<<<
adview2: received ad
adview1: received ad
** Activity (main) Pause, UserClosed = false **
sending message to waiting queue (iad_adopened)
you can see in the logs the finish 2 is called before finish 1 but why?

i want to go on with sub reloadAds only after myappinfo_Success returned the value obj.
what am i doing wrong?

thank you

EDIT: ok i understand my problem. the myappinfo_Success event is called from a library and not when i call Wait For. so is there a possibility to tell the app to wait until a specific event is raised? or i can only do it when i call the event directly and wait until it returns an object? it would be very helpful if i could use Wait For to wait until a specific Event was raised and returned a value even if i call it from a different sub.
 
Last edited:

ilan

Expert
Licensed User
ok i think i got it,
i assume this is how i should do it:

B4X:
Sub reloadAds
    Dim myappinfo As getappinfo
    myappinfo.Initialize(Me,"myappinfo","www.sagital.mysalarynew")

    Wait For (myappinfo) myappinfo_Success(obj() As Object)
    If obj.Length > 0 Then
        LogColor("finish 1",Colors.Red)
        Dim l As List
        l.Initialize
    
        For i = 0 To obj.length - 1
            l.Add(obj(i))
        Next
    
        File.WriteList(File.DirInternal,"myad" & adPos & ".txt", l)
    End If

    LogColor("finish 2",Colors.Green)
End Sub
i get in the logs the right result:

** Service (starter) Start **
** Service (firebasemessaging) Create **
** Service (firebasemessaging) Start **
*** Service (loadadmodule) Create ***
** Service (loadadmodule) Start **
Message arrived
Message data: {body=www.sagital.mysalarynew|www.sagital.scrshield, title=myads}
** Service (loadadmodule) Start **
*** Service (httputils2service) Create ***
** Service (httputils2service) Start **
installs: 5,000 - 10,000
installs: 5,000 - 10,000
finish 1
finish 2
 

ilan

Expert
Licensed User
Ilan the syntax in your first post is wrong.
Yes i understood where i was wrong its simple to understand after you take a closer look on the example in post nr 1.

The resumeabke sub is a huge addition to make our work easier.

I wonder if its a unique feature of b4x or its something taken from Java??

If i would make an app in java is it available there?

Thank you
 

leitor79

Active Member
Licensed User
Hello!

I've just received the 7.30 update and I've read the changelog and this post, and I still don't get the ResumableSub type advantage/need... I mean, I see the different syntax, but I don't understand what could be achieved with a ResumableSub that couldn't be done without it. I've read comments about lot of ideas or uses, but I don't see the difference between this:

B4X:
Sub Button1_Click
   Wait For(Sum(1, 2)) Complete (Result As Int)
   Log("result: " & Result)
   Log("after sum")
End Sub
and this

B4X:
Sub Button1_Click
   Dim rs As ResumableSub = Sum(1, 2)
   Wait For(rs) Complete (Result As Int)
   Log("result: " & Result)
   Log("after sum")
End Sub
Can anyone give me a tip?


Thank you very much!
 
Top