Android Question [SOLVED] Seriously, how does Resumable Subs work?

Sandman

Expert
Licensed User
Longtime User
I had this all working, but when re-factoring and doing a slight bit of abstraction I started to confuse myself beyond belief. Now I feel I have reached a point where I understand nothing on how Resumable Subs work. I appreciate if someone could explain where I'm off. :)

I have a class (CLNET) defined in my Starter that handles my network requests, and at it's core, there's a generic sub that does the HttpJob handling.

For my situation, imagine a sub in an Activity calling a sub in my net class, which is then calling another sub in the same class. The last sub does the HttpJob and waits for it to finish, and the result of that should pour all the way back to the sub in the activity, which is waiting for the result.


This my structure (simplified):

In the Main activity

B4X:
Sub btnExample_Click

    Wait For (Starter.CLNET.ExampleJob(Starter.SomeValue)) complete (result As Map)
    doSomething(result)

End Sub


In CLNET

B4X:
Sub ExampleJob (SomeValue as string) As ResumableSub

    Dim url as string = "http://www.example.com/" & SomeValue

    Wait For (genericRequest(url)) complete (result As Map)
    return result

End Sub


Private Sub genericRequest (url as string) As ResumableSub

    Dim job as HttpJob
    job.Initialize("", Me)
    job.Download(url)

    Wait For (job) JobDone(job As HttpJob)

    Dim result as Map = jobToMap(job)
    Return result

End Sub


I've tried lots of variations of this. At one point it kind of felt logical that only the genericRequest should do any Wait For'ing, because the btnExample_Click and ExampleJob would just wait for it to finish. Like so:

In the Main activity

B4X:
Sub btnExample_Click

    Dim result As Map = Starter.CLNET.ExampleJob(Starter.SomeValue)
    doSomething(result)

End Sub


In CLNET

B4X:
Sub ExampleJob (SomeValue as string) As Map

    Dim url as string = "http://www.example.com/" & SomeValue

    return genericRequest(url)

End Sub

Private Sub genericRequest (url as string) As ResumableSub

    Dim job as HttpJob
    job.Initialize("", Me)
    job.Download(url)

    Wait For (job) JobDone(job As HttpJob)

    Dim result as Map = jobToMap(job)
    Return result

End Sub


But that didn't work as expected. Like I said, I'm getting more and more confused. I'm sure there's something obvious I'm missing on how to think of the Resumable Subs and code flow. All help appreciated, preferably attached to an explanation. :)
 
Last edited:

Sandman

Expert
Licensed User
Longtime User
Why are you removing the 'sub' keyword in the posted code?

Just a small case of late night fatigue. I've added them now.

Ok, good to hear that the first two seems correct. My experience is that the value doesn't ever pour all the way back down, so I was thinking that perhaps it wasn't possible to chain Wait For into a nested flow like I did. I'll try some more and see what happens.
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
Logs are your best friend when things start getting a bit confusing...
Try to log the result in every sub to see where it gets lost, so you can know where to change your code if needed
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
Logs are your best friend when things start getting a bit confusing...
Try to log the result in every sub to see where it gets lost, so you can know where to change your code if needed

Oh, believe me, at this point I have more Logs than actual code. ;-)

However, I just wrapped each Wait For in two logs to see the flow more clearly:

B4X:
Sub btnExample_Click

    Log("btnExample_Click: About to wait for ExampleJob")
    Wait For (Starter.CLNET.ExampleJob(Starter.SomeValue)) complete (result As Map)
    Log("btnExample_Click: Done waiting for ExampleJob") ' <-- This never shows
    doSomething(result)

End Sub


In CLNET

B4X:
Sub ExampleJob (SomeValue as string) As ResumableSub

    Dim url as string = "http://www.example.com/" & SomeValue

    Log("ExampleJob: About to wait for genericRequest")
    Wait For (genericRequest(url)) complete (result As Map)
    Log("ExampleJob: Done waiting for genericRequest")
    return result ' <-- Breakpoint here confirms this value as correct

End Sub


Private Sub genericRequest (url as string) As ResumableSub

    Dim job as HttpJob
    job.Initialize("", Me)
    job.Download(url)

    Log("genericRequest: About to wait for HttpJob")
    Wait For (job) JobDone(job As HttpJob)
    Log("genericRequest: Done waiting for HttpJob")

    Dim result as Map = jobToMap(job)
    Return result' <-- Breakpoint here confirms this value as correct

End Sub

The code in btnExample_Click never completes and continues. And I can't figure out why...

Below is the output from the Log. As you can see, the line btnExample_Click: Done waiting for ExampleJob is missing.

B4X:
btnExample_Click: About to wait for ExampleJob
ExampleJob: About to wait for genericRequest
genericRequest: About to wait for HttpJob
genericRequest: Done waiting for HttpJob
ExampleJob: Done waiting for genericRequest
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
While reducing my project to a skeleton version I found the problem. I still don't understand why it is a problem though, I sure would like to do so.

If I have this code in an Activity, the last Log is never displayed:

B4X:
Sub Activity_Resume
    lookup
    Activity.Finish
End Sub

Sub lookup
    Log("Outermost: About to wait for CLNET.example")
    Wait For (Starter.CLNET.example("avalue")) complete (result As String)
    Log("Outermost: Done waiting for CLNET.example") ' <-- Not displayed
End Sub

But if I move the Activity.Finish to be last in lookup instead it works just fine:

B4X:
Sub Activity_Resume
    lookup
End Sub

Sub lookup
    Log("Outermost: About to wait for CLNET.example")
    Wait For (Starter.CLNET.example("avalue")) complete (result As String)
    Log("Outermost: Done waiting for CLNET.example")' <-- Is displayed
    Activity.Finish ' <-- moved from Activity_Resume
End Sub

Shouldn't these two code examples be identical?

(@Erel: I'm guessing you don't want/need my example project given what I just wrote. Let me know if that's not correct and I'll upload it.)
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
in the first example, you are not waiting for the look up to end, and thus, the lookup sub never returns the control to the calling sub.
Also, the OS may be not considering the Activity finish since you had it in The Resume sub... which would seem ilogical.

By placing the Activity.finish inside the lookup sub, the sub proceeds up to completion and after the wait for is done, the activity finishes.

This is the way I see it, but I can be way off, as I often do!
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
in the first example, you are not waiting for the look up to end, and thus, the lookup sub never returns the control to the calling sub.

I'm not? Well, I'm not specifically waiting for lookup to end, but in lookup itself I do the whole complete thing to wait for a returning value. That's not enough to "pause" the execution in Activity_Resume? I'd also have to call lookup using a Wait For, and wait for a fake value (so the Activity.Finish isn't run prematurely)?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Your code is indeed wrong.

Remember that Wait For is equivalent to Return from the calling sub perspective.
So Activity.Finish is called before the lookup sub is resumed.

It is very simple to fix:
B4X:
Sub Activity_Resume
    Wait For(lookup) Complete (Result As Null)
    Activity.Finish
End Sub

Sub lookup As Resumable
    Log("Outermost: About to wait for CLNET.example")
    Wait For (Starter.CLNET.example("avalue")) complete (result As String)
    Log("Outermost: Done waiting for CLNET.example") 
    Return Null
End Sub
 
Upvote 0
Top