Android Tutorial [B4X] OkHttpUtils2 with Wait For

Status
Not open for further replies.

Erel

Administrator
Staff member
Licensed User

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.

download.gif
 
Last edited:

FrankDev

Active Member
Licensed 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

Administrator
Staff member
Licensed 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
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

Administrator
Staff member
Licensed User

PABLO2013

Active Member
Licensed 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:

PABLO2013

Active Member
Licensed 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