Android Question How to wait HTTPJOB execution?

FrankBerra

Active Member
Licensed User
Longtime User
Hi all

i created a Sub that authenticates on remote server through HTTPJOB. It is something like this

B4X:
Sub auth

FlagAuth=False
Auth.PostString("http://xxx.xxx.xxx.xxx/auth.php", "user=" & User & "&pass=" & Pass)

    If FlagAuth=True Then
        Return True
    Else
        Return False
    End If

End sub

where FlagAuth is set into Job.Done routine.

The problem is that the program don't wait for "Auth.PostString" to finish and it continues the execution and the "Sub auth" returns "False" instead of "True" even it is authenticated correctly

How can i wait the execution of the Auth.Postring and then go ahead with the rest of the code?

Thanks in advance
 
Last edited:

KMatle

Expert
Licensed User
Longtime User
B4X:
Sub JobDone(Job As HttpJob)
    ProgressDialogHide
 
    If Job.Success Then
        Dim res As String, action As String
        res = Job.GetString
        Log("Back from Job:" & Job.JobName )
        Log("Response from server: " & res)

Using httputils the response of the php script is stored in "res"

You can check the job coming back (f.e. "Login" and then check if res = "Y" (or return an JSON array with "Auth:True" or similar)

The workflow is:

1. Call a php script

2. do nothing

3. JobDone is called when the Job is finished

4. Check if Job.success = true

5. Check the content of "res" (coming from the php via "print" or "JSON_ENCODE"
 
Upvote 0

FrankBerra

Active Member
Licensed User
Longtime User
Ok but my problem is not related to How to retrive data from php. (I am already able to do that)
My problem is that the execution of code in "sub Auth" continues even if the job hasn't finished
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
The call is async. that´´s how android works. You need to deal with that... put the auth-routine into the jobdone sub and call another sub from there if auth is done... Or set a global flag....
 
Upvote 0

IslandMedic

Member
Licensed User
Longtime User
B4X:
Sub JobDone(Job As HttpJob)
    ProgressDialogHide

    If Job.Success Then
        Dim res As String, action As String
        res = Job.GetString
        Log("Back from Job:" & Job.JobName )
        Log("Response from server: " & res)

Using httputils the response of the php script is stored in "res"

You can check the job coming back (f.e. "Login" and then check if res = "Y" (or return an JSON array with "Auth:True" or similar)

The workflow is:

1. Call a php script

2. do nothing

3. JobDone is called when the Job is finished

4. Check if Job.success = true

5. Check the content of "res" (coming from the php via "print" or "JSON_ENCODE"


In this example, res holds the returned string. How do I access res from outside of Job.done? I know this is a silly question but I just can't figure out how to access the contents. The next step is to decode the json string being returned. Can't do that untill I can get at the returned string from the post request. thanks for the help.
B4X:
Activity.LoadLayout("Layout1")

    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)

    'Send a POST request
    job1.Initialize("Job1", Me)
    job1.PostString("http://www.jjjjj.org/lifecad.php", "key=a334|||~~&query=select * from staff")

    Dim cMessage As String = "Please wait..."
    InProgress = True
    ProgressDialogShow(cMessage)
when I do log(job1.Getstring) I get the error java.io.FileNotFoundException: : open failed: ENOENT (No such file or directory)

B4X:
Sub JobDone (Job As HttpJob)
   Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
   If Job.Success = True Then
      'print the result to the logs
     Log(Job.GetString)
      'http_results = Job.GetString
   Else
      Log("Error: " & Job.ErrorMessage)
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
   End If
   Job.Release
   ProgressDialogHide
   InProgress = False
End Sub
 
Last edited:
Upvote 0

KMatle

Expert
Licensed User
Longtime User
Dim job1 As HttpJob
----> job1.Initialize("Job1", Me)

'Send a POST request
----> #2 job1.Initialize("Job1", Me)

Do not initialize 2 times and...

For each Job you must create a new instance (Dim x as httpjob):

B4X:
Dim job1 As HttpJob
job1.Initialize("Job1", Me)
job1.PostString("http://www.jjjjj.org/lifecad.php", "key=a334|||~~&query=select * from staff")

'Next one (Dim again!)
Dim job1 As HttpJob
job1.Initialize("Job1", Me)
job1.PostString("http://www.jjjjj.org/lifecad.php", "key=a334|||~~&query=select 'George' from staff")

Explanation: The data from the job is stored in a file by the library. If you don't create a new instance via DIM the first Job gets the file and after it's deleted by the lib. The "second" one (same job) does not find the file and the exception is correct.
 
Upvote 0

IslandMedic

Member
Licensed User
Longtime User
ok that makes total sense. I took out the double init and tried again and suffered the same error. what I am doing is trying a version of unit testing. being new to this environment I have to go slow and make sure each part works as planned. the program that it is in is really simple. as you can see from the code it is just in the activity create block. once I get a appropriate response then I will parse it via Json. That is the plan any way. this is all the code I have other than a spinner on the form. I do not get anything else in the log and I never get the dialog box. I am using the bridge to test it on my galaxy tablet. Any other ideas woudl be really helpful.

thanks.

B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Layout1")
   
    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)

    'Send a POST request
    job1.PostString("http://www.xxxxx.org/lifecad.php", "key=secret&query=select * from staff")
   
    Dim cMessage As String = "Please wait..."
    InProgress = True
    ProgressDialogShow(cMessage)

    Log(job1.GetString)   <---- errrors out here  java.io.FileNotFoundException: : open failed: ENOENT (No such file or directory)

    ' If InProgress Then ... Else ... End If

    'need to process the Json data
    'Dim p As JSONParser
    'p.Initialize(job1.GetString)
    'Dim list1 As List
    'list1 = p.NextArray
    'Dim map1 As Map
    'map1 = list1.Get(0)
    'Log(map1)
    'Dim umobilenum As String
    'umobilenum = map1.Get("umobilenum")
    'Log(umobilenum)
   
    'need to load the spinner with data
   
End Sub

Sub JobDone (Job As HttpJob)
   Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
   If Job.Success = True Then
      'print the result to the logs
     Log(Job.GetString)
      'http_results = Job.GetString
   Else
      Log("Error: " & Job.ErrorMessage)
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
   End If
   Job.Release  <-  would releasing the job too early also delete the file?  I did try to comment it out and it made no difference.
   ProgressDialogHide
   InProgress = False
End Sub
 
Upvote 0

FrankBerra

Active Member
Licensed User
Longtime User
You should use job1.GetString only after job execution is finished.
So you have to move the code Log(job1.GetString) into the Sub JobDone
 
Upvote 0

IslandMedic

Member
Licensed User
Longtime User
ok, thanks, it was a combination of errors. first I initialized twice then I did the get string in the wrong place. thanks for the help it is appreciated.
 
Upvote 0

IslandMedic

Member
Licensed User
Longtime User
you will notice the following in jobsdone. 'http_results = Job.GetString I init this variable in Process_Globals Public http_results As String. The idea is then have the results in a global variable that I can then use when I am back in the activity start module. when I go to log(http_result) I get nothing logged. If I do the same in the jobdone sub the variable is set and prints out in the logs just fine. So why won't the value transfer out of the sub via the global variable when i have declared it a process global variable? I think I just dont understand how to reference a global process variable. I know that this is a RTFM question, and I have tried both the tutorial and the user guide. I have been googling like a bugger. It must be that I am missing something so simple that it isn't really explicitly explained. I have to admit I am very old school "apple basic circa 1985" and learning oop has been a challenge.

thanks

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
   
    Public http_results As String
   
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Layout1")
   
    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)

    'Send a POST request
    job1.PostString("http://www.","  from staff")
   
    Dim cMessage As String = "Please wait...Loading Network Data"
    ProgressDialogShow(cMessage)
   
    Log(http_results)
End Sub

Sub JobDone (Job As HttpJob)
   Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
   If Job.Success = True Then
      http_results = Job.GetString
   Else
      Log("Error: " & Job.ErrorMessage)
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
   End If
   Job.Release
   ProgressDialogHide
End Sub
 
Upvote 0

FrankBerra

Active Member
Licensed User
Longtime User
Android execution is different: when you call job1.PostString("http://www."," from staff") the program continues with the following instuctions
B4X:
Dim cMessage AsString = "Please wait...Loading Network Data"ProgressDialogShow(cMessage)
Log(http_results)
even if the PostString job isn't finished and in parallel it is executed the routine to send data to your server.
So if you put Log(http_results) outside the JobDone sub you don't log anything because this instruction is executed before the end of the PostString job.

To log results you MUST wait until JobDone is called and then execute something else for example:
B4X:
Sub JobDone (Job AsHttpJob)
Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
If Job.Success = True Then
   http_results = Job.GetString
   DoSomethingElse 'call the sub with other instructions to execute
Else
   Log("Error: " & Job.ErrorMessage)ToastMessageShow("Error: " & Job.ErrorMessage, True)
EndIf
   Job.ReleaseProgressDialogHide

End Sub

Sub DoSomethingElse
    Log(http_results)
End Sub
 
Upvote 0

IslandMedic

Member
Licensed User
Longtime User
OK, I see what you are saying and that makes sense. so what I should do now is then explain what I am trying to achieve from a workflow perspective. Then it will give me a fighting chance to be successful. Remember I am a top down programmer and it is hard to think multiple lines of code at once.

I want to have a routine that I can call when ever I need server data. Some of my server calls can happen in the back ground but most of them is I need to wait for the reply so I can continue on.

It would be nice to be able to send any "query statement" to the routine and have a json formatted data returned back to the point of the call. Trick is how to wait for that to fully execute or time out. What I am trying to do is make a neat and tidy routine that will make an async action into one that is not. call me crazy I know. Then I can act accordingly. my challenge is to merge top down coding with the asynchronous coding. This i know is where I am struggling.

start program -> call server and ask for inital setup values ->wait till I get the necessary data or error out -> use the date to configure the app -> move into a standby state waiting for user activity.

I will do more reading and see if i can learn how this is done. Any pointers would be appreciated.
 
Upvote 0

FrankBerra

Active Member
Licensed User
Longtime User
You are already on the right way. The example above is already doing what you are asking for.
1. Start the program (it start from Activity_create)
2. Call server (job1.PostString("http://www."," from staff"))
3. Wait until the server responds (your data will be available ONLY after sub JobDone is called, and it will be called automatically after server responds)
3b. Call a soubroutine (to configure your app) where you pass your data trough public variable or with the statement DoSomethingElse(http_results)
4. After the Sub DoSomethingElse ends the app move into a standby state and nothing else will be executed
 
Upvote 0
Top