Android Tutorial [B4X] OkHttpUtils2 with Wait For

Status
Not open for further replies.

Downloading resources is simpler with the new Resumable Subs feature.

Using Wait For we can wait for the JobDone event in the same sub that started the download.
No longer is it needed to have a single sub that handles all requests results.

Simplest example:
B4X:
Dim j As HttpJob
j.Initialize("", Me)
j.Download("https://www.google.com")
Wait For (j) JobDone(j As HttpJob)
If j.Success Then
   Log(j.GetString)
End If
j.Release


Example of downloading a quote from a quotes service:
B4X:
Sub DownloadQuote
   Dim j As HttpJob
   j.Initialize("", Me) 'name is empty as it is no longer needed
   j.Download("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand")
   Wait For (j) JobDone(j As HttpJob)
   If j.Success Then
     'The result is a json string. We parse it and log the fields.
     Dim jp As JSONParser
     jp.Initialize(j.GetString)
     Dim quotes As List = jp.NextArray
     For Each quot As Map In quotes
       Log("Title: " & quot.Get("title"))
       Log("Content: " & quot.Get("content"))
     Next
   End If
   j.Release
End Sub

Note that the HttpJob object is a local variable. This is the recommended way to create HttpJobs as it allows us to set the sender filter parameter (read more in the tutorial about resumable subs).
The same sub can be called multiple times and also other subs that send HttpJobs. As each HttpJob is unique, all the events will reach the correct place.

Downloading two resources, one after another:
B4X:
Sub DownloadTwoLinks
   Dim j As HttpJob
   j.Initialize("", Me) 'name is empty as it is no longer needed
   j.Download("https://www.google.com")
   Wait For (j) JobDone(j As HttpJob)
   If j.Success Then
     Log(j.GetString)
   End If
   j.Release
   'second request
   Dim j As HttpJob 'redim and initialize
   j.Initialize("", Me)
   j.Download("https://www.duckduckgo.com")
   Wait For (j) JobDone(j As HttpJob)
   If j.Success Then
     Log(j.GetString)
   End If
   j.Release
End Sub

Now for a very common question. How to download a list of resources, one by one?
Simple:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   DownloadMany(Array("http://www.google.com", "http://duckduckgo.com", "http://bing.com"))
End Sub

Sub DownloadMany (links As List)
   For Each link As String In links
     Dim j As HttpJob
     j.Initialize("", Me) 'name is empty as it is no longer needed
     j.Download(link)
     Wait For (j) JobDone(j As HttpJob)
     If j.Success Then
       Log("Current link: " & link)
       Log(j.GetString)
     End If
     j.Release
   Next
End Sub

A sub that downloads an image and sets it to an ImageView:

B4X:
Sub DownloadImage(Link As String, iv As ImageView)
   Dim j As HttpJob
   j.Initialize("", Me)
   j.Download(Link)
   Wait For (j) JobDone(j As HttpJob)
   If j.Success Then
     iv.Bitmap = j.GetBitmap
   End If
   j.Release
End Sub

Example of saving the downloaded file:
B4X:
Sub DownloadAndSaveFile (Link As String)
   Dim j As HttpJob
   j.Initialize("", Me)
   j.Download(Link)
   Wait For (j) JobDone(j As HttpJob)
   If j.Success Then
       Dim out As OutputStream = File.OpenOutput(File.DirInternal, "filename.dat", False)
     File.Copy2(j.GetInputStream, out)
     out.Close '<------ very important
   End If
   j.Release
End Sub

The nice thing about this sub, and all above subs as well, is that they can be called multiple times:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("1")
   DownloadImage("https://b4x-4c17.kxcdn.com/android/forum/data/avatars/m/0/1.jpg?1469350209", ImageView1)
   DownloadImage("https://b4x-4c17.kxcdn.com/images3/code.png", ImageView2)
End Sub

The images will be downloaded concurrently.

Tip about the code flow: Sleep and Wait For are equivalent to calling Return from the calling sub perspective.
 
Last edited:

FrankDev

Active Member
Licensed User
Longtime User
Which is when one makes several requests but only one source does not answer.
One has only one sub-error for all queries. So a 'job_RequestError' routine.
Then you have to make a differentiation again from which request now the error was triggered.

sorry Translated with google translate

regards Frank
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
So a 'job_RequestError' routine.
There is no such thing. There is only a JobDone event. This is why you need to check that Job.Success is true.

Which is when one makes several requests but only one source does not answer.
This is handled in the above code.
This is the reason for the sender filter parameter (j). The correct event will reach the correct sub based on the sender filter.

You can read about the sender filter here: https://www.b4x.com/android/forum/threads/b4x-resumable-subs-sleep-wait-for.78601/#content
 
Last edited:

FrankDev

Active Member
Licensed User
Longtime User
Hi Erel
the way is clear. IN the Sub will be queried whether it was successful. But what if not?
If I want to know that the request is not successful.
the 'job_request_error' routine is raised even after a time (timeout). I see that it didn't work.
now I would have to look with a timer if after a certain things which are.
I would like to display data to the user.
now waits for the query just what?
I want to say the user... Hey... the server is not responding...
try it later?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User

FrankDev

Active Member
Licensed User
Longtime User
Sorry, last question.

This works only for downloads or (auch) for HTTPPost requests ?
 

demasi

Active Member
Licensed User
Longtime User
Thank you! This is a major improvement and a long waited feature.
Now our programs will be easier to make, read and maintain.
 

PABLO2013

Well-Known Member
Licensed User
Longtime User
Regards, I have been trying to do this but I would like to know that I will be doing wrong ... thanks
What I am trying to do is that the queries are one at a time...
And see the results one at a time...tks

B4X:
Sub INICIO_MouseClicked (EventData As MouseEvent)
For i=1 To 5
    DIR(12)="https://www.123.com/123/"&i&"-123-"&i&"-.html"
    Dim job As HttpJob
    Wait For (job) JobDone(job As HttpJob) '-------------------
    job.Initialize("123", Me)
    job.Download(DIR(12))
Next
End Sub

B4X:
Sub JobDone(Job As HttpJob)

    Select Job.JobName

        Case "123"

            If Job.Success = True Then

                Log(Job.Tag)
                DIR(12)=Job.GetString
                   T1=Mid(DIR(12), DIR(12).IndexOf("<title>"),100)
                T2=Mid(T1,0,T1.IndexOf("</title>")).Replace("&quot;"," PULG.").Replace("- .......","").Replace("<title>","").Replace("&amp;","&").Trim
                Log(T2)
       
            Else
           
                Log("Error:************************************************")
                Log(Job.Tag)
                Log("Error:************************************************")
            End If
            Job.Release

        Case "456"

            If Job.Success = True Then

                Log(Job.Tag)
                DIR(12)=Job.GetString
                   T1=Mid(DIR(12), DIR(12).IndexOf("<title>"),100)
                T2=Mid(T1,0,T1.IndexOf("</title>")).Replace("&quot;"," PULG.").Replace("- .......","").Replace("<title>","").Replace("&amp;","&").Trim
                Log(T2)

            Else
           
                Log("Error:************************************************")
                Log(Job.Tag)
                Log("Error:************************************************")
       
            End If
       
            Job.Release

        End Select
End Sub
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
B4X:
    Dim job As HttpJob
    job.Initialize("123", Me)
    job.Download(DIR(12))
    Wait For (job) JobDone(job As HttpJob) '-------------------
    If job.success then
        '' my code....
    end if
    job.release

PD: It is better (ALWAYS!) to start a NEW thread for each question.
 

PABLO2013

Well-Known Member
Licensed User
Longtime User
Thank you donmanfred ... sorry for understanding little ... but where place for ..... next

What I want is to use to "WaitFor (job) JobDone(job AsHttpJob)"

Request and scrape the information of 5 pages in an automatic but individual way

For 1 to 5
1. Read page server
2. Scrape the information on the page
3.continue with the following
Next

What happens to me is that it runs all the entire "for ... next" at one time and the server generates an error or block


thank you
 
Status
Not open for further replies.
Top