Android Question Troubles with HttpJob

umberto_dev

Member
Licensed User
Longtime User
Hello,
I'm having a problem since I have to execute several HttpJobs according to several states.
Some are executed, others not.
I call some subroutines, program enters them but JobDone is not always invoked.
In this case, job1 is executed, while jobt not.
The sequence is job1 (always), jobt in some cases.
I receive the log message Readfile but not the one from JobDOne.

B4X:
Sub getToken
    Dim jobt As HttpJob
    jobt.Initialize("jobt", Me)
    jobt.Download(server & "token.php")
    Log ("Jobt su getToken")
End Sub

Sub ReadFile
    Dim job1 As HttpJob
    job1.Initialize("job1", Me)
    job1.Download(server&"xxxx.txt")
    Log ("Job1 su ReadFile")
End Sub

B4X:
Sub JobDone (Job As HttpJob)
    Dim qResult As String
    Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
    If Job.Success = True Then
        Select Job.JobName
            Case "job1"
                tmr.Enabled = False
                Dim os As OutputStream
                os = File.OpenOutput(File.DirDefaultExternal, "xxx.txt", False)
                File.Copy2(Job.GetInputStream, os)
                os.Close
                Job.Release
                Log ("job1 executed on JobDone")
                tmr.Enabled = True
            Case "jobt"
                tmr.Enabled = False
                token = Job.GetString
                Job.Release
                Log ("jobt executed on JobDone")
                tmr.Enabled = True
            Case "job3"
                tmr.Enabled = False
                Dim os As OutputStream
                os = File.OpenOutput(File.DirDefaultExternal, "local.txt", False)
                File.Copy2(Job.GetInputStream, os)
                os.Close
                Job.Release
                Log ("job3 executed on JobDone ")
                tmr.Enabled = True
                checkCustom
            Case "job4"
                tmr.Enabled = False
                Dim out As OutputStream = File.OpenOutput(File.DirDefaultExternal, "ext.jpg", False)
                File.Copy2(Job.GetInputStream, out)
                out.Close
                bann = "ext.jpg"
                Log ("job4 executed on JobDone - image downloaded")
        End Select
    Else
        ToastMessageShow("Error: " & Job.ErrorMessage, True)
        Job.Release
    End If
End Sub

Any idea?
Thank you
 

sorex

Expert
Licensed User
Longtime User
are you executing all of them at once?

you better call readFile in the jobdone sub part for getToken.

you don't have control ofwhat ends first if you call them right after each other.
 
Upvote 0

umberto_dev

Member
Licensed User
Longtime User
Thank you Sorex.
No, it happens in different times. Each job is executed on it's own.
In sequence ReadFile comes first (always), then the app makes some activities with SQLLite, then and if the app has not been initalized (once, after the first setup, and never else), it invokes getToken, then when a button is pressed, it loads some other settings (job3 and job4), and these ones work. The only problem is with getToken.
Is there anything I have to release before starting another HttpJob? Like closing for files or connections for a database, I'm getting crazy and it's a couple of days I'm facing with this problem.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
What version of B4A are you using?
 
Upvote 0

umberto_dev

Member
Licensed User
Longtime User
Thank you both, OliverA and Erel
@OliverA version 7.30
@Erel. I did this but I got no success:

B4X:
Sub getToken
Dim j As HttpJob
j.Initialize("", Me)
j.Download(server & "token.php")
Wait For (j) JobDone(j As HttpJob)
If j.Success Then
    token = j.GetString
    Log(token)
End If
j.Release
End Sub

It enters this Sub, and on Wait it returns but no value is read and it doesn't execute all the code underneath.
I tried with a do Until j.Success instead of a Wait, in order to circumvent a resumable sub, but it envelops into an infinite loop.
I even thought it was something about Android, but I tested it on two different devices, different OS versions, with the same result.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
The most likely explanation is that you are not getting a 200 return code on you HTTP call. The Success flag of a job is only true if a 200 code is returned. For any other codes, you'll get a false. Change your if code to this and see what error message you are getting back from the server:
B4X:
If j.Success Then
  token = j.GetString
  Log(token)
Else
  Log($"Something went wrong: ${job.ErrorMessage}"$)
End If
 
Upvote 0

umberto_dev

Member
Licensed User
Longtime User
Thank you OliverA.
Nope. I placed the whole address into a string, to check if there was something wrong, since the webserver is a Linux one, so it's case sensitive, but it's right and the browser returns the right value, so it's a 200 return code.
I also used the Else statement removing the Wait. I paused on the IF cycle to read the j value. The most important thing seems to be the req/uri, All of the connection string seems OK, maybe the bottom part could be more interesting:
b4amessage.jpg

I don't see anything wrong in the code, but if it doesn't work I'm wrong. I still believe there's something wrong with the first routine (ReadFile), but there is the Job.Release command, so it should release the resource.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
It enters this Sub, and on Wait it returns but no value is read and it doesn't execute all the code underneath.
I tried with a do Until j.Success instead of a Wait, in order to circumvent a resumable sub, but it envelops into an infinite loop.
Right here you are telling me that j.Success is FALSE, since waiting for j.Success to be TRUE gives you an endless loop. If j.Success is FALSE, then j.ErrorMessage should give you something (in my post #7, I wrongly used job.ErrorMessage instead of j.ErrorMessage). Also, how do you know that it does not execute the code below?
I also used the Else statement removing the Wait.
Why would you remove the wait? Call getToken with the Wait in place and see if j.Success is True or False. Which one is it? If it is True, what is the output of j.GetString? If it is false, what is the output of j.ErrorMesasge?

Try the below code and, barring any coding mistakes on my end, what are the log outputs?

B4X:
Sub getToken
  Log("Entering getToken...")
  Dim j As HttpJob
  j.Initialize("", Me)
  Log($"URL: ${server}token.php"$)
  j.Download(server & "token.php")
  Log("Starting to wait...")
  Wait For (j) JobDone(j As HttpJob)
  Log("Done waiting...")
  If j.Success Then
    Log("200 code was returned")
    token = j.GetString
    Log($"And the token is: ${token}"$)
  Else
    Log("We have a problem Houston...")
    Log($"Something went wrong: ${j.ErrorMessage}"$)
  End If
  j.Release
  Log("Exiting getToken...")
End Sub
 
Last edited:
Upvote 0

umberto_dev

Member
Licensed User
Longtime User
None. the only message is "Starting to wait..." .
I already placed Logs ans break points everywhere, this is why I wrote it returns nothing.
Removing the Wait, the j.ErrorMessage is an empty string.

Houston I have a problem!! Feeling more like Major Tom than Apollo crews, at least they landed. :(
I'm really getting crazy with this piece of code and I really appreciate your help.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
It's time to isolate the problem. All other HttpJob's need to be commented out and the JobDone function needs to be commented out. The only place you should have a HttpJob in your code is the getToken method. Then you just need to call up this (getToken) method and go from there.
 
Upvote 0

umberto_dev

Member
Licensed User
Longtime User
Thank you OliverA, I'm really grateful for your help.
I wrote a new app, doing just getToken, and, of course, it works.
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim token As String
    Dim job2 As HttpJob
    job2.Initialize("job2",Me)
    job2.Download(server&"token.php")
    Wait For (job2) JobDone(j As HttpJob)
    If j.Success Then
        Log("200 code was returned")
        token = j.GetString
        Log($"And the token is: ${token}"$)
    Else
        Log("We have a problem Houston...")
        Log($"Something went wrong: ${j.ErrorMessage}"$)
    End If
    j.Release
End Sub
I returned to this app, I've isolated all other HttpJobs, and JobDone and, you won't believe, it still doesn't work,
It's more than 6 hours I'm doing tests, modifying code.
This is the only one related to HttpJob, all the others have been converted as Remarks:
B4X:
Sub insertSQL(vers As Int)
    Dim txt As String = server&"token.php"
    Dim job2 As HttpJob
    job2.Initialize("job2",Me)
    job2.Download(txt)
    Log("Let's wait")
    Wait For (job2) JobDone(j As HttpJob)
    If j.Success Then
        Log("200 code was returned")
        token = j.GetString
        Log($"And the token is: ${token}"$)
    Else
        Log("We have a problem Houston...")
        Log($"Something went wrong: ${j.ErrorMessage}"$)
    End If
    j.Release
End Sub
When insertSQL is invoked, it doesn't pass the Wait. It bounces from the beginning to Wait, If j.Success is never reached.
At moment this app has more than 2,400 lines of code. A similar app, with less code, but with the same beginning part (and this is the beginning) works. I'm even thinking of problems with heap memory. It's like j gets lost somewhere. The question is "why just this job?".
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Do you by chance have a global variable named job2, anywhere? Also, change
B4X:
job2.Initialize("job2",Me)
to
B4X:
job2.Initialize("",Me)
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
When insertSQL is invoked, it doesn't pass the Wait
How is insertSQL called? Technically, once you reach the Wait For in the insertSQL, the application continues with the statement AFTER the insertSQL call until the JobDone event is raised. Where is insertSQL located? Code module? Class? Etc.?
 
Upvote 0

umberto_dev

Member
Licensed User
Longtime User
Hi OliverA,
all jobs variables are local and private, and each one is used for a single purpose, so there is job1, job2, etc.
InsertSQL is a method called by Activity_Create if the app has not been initializated (once in its life) and after a check for Internet availability and continues inserting a record into a SQLlite DB table with data returned by this service.
I didn' reported other code, but it follows this way:
B4X:
    sql.BeginTransaction
    txt = "INSERT OR REPLACE INTO tblToken (id,token,version,language) VALUES (1,'" & token  & "'," & vers & ",0)"
    sql.ExecNonQuery(txt)
    sql.TransactionSuccessful
    sql.EndTransaction
of course both vers and token are public and global and this code works.
As I wrote in other apps all this works fine and smooth, this is why I can't explain this trouble.
I also tried with an anonimous name ("" instead od "job2"), without any success.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Yeah, I'm starting to grasp at straws here, hoping to get lucky. It may be time to have someone else look at the code (overall) and see if they can reproduce, find, and/or solve the issue.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Removing the Wait, the j.ErrorMessage is an empty string.
That's expected. The result will never be ready if you don't wait for the event.

Is it possible that the activity is not in the foreground when the result arrives?
Move this code to Service_Create of the starter service and try it again.
 
Upvote 0

umberto_dev

Member
Licensed User
Longtime User
Hello OliverA and Erel,
thank you very much for your precious help.
I found that if I use the full code into a calling routine it works, while if I create a Subroutine (or a method) to perform the job, even if I use global variables it doesn't.
By the way, even if it's not very neat and elegant, now, with your help and advices, I found a way to let this app work.
The wait on resumable subs it's a great improvement, since with the previous code I had to use timers to keep a routine waiting until data were collected by a remote server.
Thank you again.
 
Upvote 0
Top