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

Discussion in 'Tutorials & Examples' started by Erel, Aug 10, 2017.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Starting from B4A v7.30, B4J V5.90 and B4i V4.30 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:
    Code:
    Sub Button1_Click
    Sum(
    12)
    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:
    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.
    Code:
    Sub Button1_Click
       
    Wait For(Sum(12)) 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:
    The above Button1_Click code is equivalent to:
    Code:
    Sub Button1_Click
       
    Dim rs As ResumableSub = Sum(12)
       
    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: Aug 25, 2017
  2. victormedranop

    victormedranop Active Member Licensed User

    This. Really solve para problems.
     
  3. jahswani

    jahswani Active Member Licensed User

    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: Aug 10, 2017
  4. tucano2000

    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
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    The customer is always right :)

    (This is not really the place for this discussion.) This phrase is currently not localizable.
     
    stingrae and miker2069 like this.
  6. johndb

    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.
     
  7. Levit

    Levit Member Licensed User

    It is coming better and better.... and never say never.
     
    jahswani likes this.
  8. Rantor777

    Rantor777 Member Licensed User

    Very handy. Lots of ideas. Thanks Erel.
     
    Ahmad-Ng likes this.
  9. Javier Donayre

    Javier Donayre Member Licensed User

    This is an excellent solution for certain routines where a kind of semaphore is required in the internal flow of data. Many Thanks, Erel!!
     
    jahswani likes this.
  10. GuyBooth

    GuyBooth Active Member Licensed User

    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:

    Code:
    ''' 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):
    Code:
    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:
    Code:
    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:
    Code:
    ' 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 StringAs 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:
    Code:
    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?
     
  11. Erel

    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.

    Code:
    Wait For (CallSub2(TMM_Connections, "Display_OKMessageAsync""Test")) Complete (Result As String)
     
    Last edited: Aug 16, 2017
    GuyBooth likes this.
  12. GuyBooth

    GuyBooth Active Member Licensed User

    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".
     
    Erel likes this.
  13. Erel

    Erel Administrator Staff Member Licensed User

    You are correct. Fixed.
     
  14. ilan

    ilan Expert Licensed User

    hi, i have a question related to ResumeableSub

    this is my code:

    Code:
    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:

    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: Aug 17, 2017
  15. ilan

    ilan Expert Licensed User

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

    Code:
    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:

     
  16. Erel

    Erel Administrator Staff Member Licensed User

    Ilan the syntax in your first post is wrong. I see that you solved it in a different way. If you want to further discuss it then please start a new thread.
     
  17. ilan

    ilan Expert Licensed User

    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
     
  18. Erel

    Erel Administrator Staff Member Licensed User

    It is unique to B4X compiler.

    No.
     
  19. leitor79

    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:

    Code:
    Sub Button1_Click
       
    Wait For(Sum(12)) Complete (Result As Int)
       
    Log("result: " & Result)
       
    Log("after sum")
    End Sub
    and this

    Code:
    Sub Button1_Click
       
    Dim rs As ResumableSub = Sum(12)
       
    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!
     
  20. Erel

    Erel Administrator Staff Member Licensed User

    This is not the correct place for your question. Please start a new thread in the questions forum.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice