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:

MhdBoy

Member
Licensed User
Longtime User
hi
how i can call Release method for wait for in other subs?
i have an app that have lots of post and if i open a post and just close the post activity before load complete after i back to previous activity and Wait for done automaticaly
 

M.LAZ

Active Member
Licensed User
Longtime User

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


could i use Download2 with DownloadMany? because i have to send parameters with this request .
 

DonManfred

Expert
Licensed User
Longtime User
Please start a new thread for any question you have.

Instead of a list of URLs you can use a List of Maps (holding the url and all other parameters).
You can adapt downloadmany to add the additional parameters based on the Map-contents.
 

sorex

Expert
Licensed User
Longtime User
Thanks for the implementation of this wait for method.

It makes more sense to group the response code with the actual call instead of stuffing it all in the jobdone sub.
 

skaliwag

Member
Licensed User
Longtime User
Will the resources held by a HttpJob be automatically released when the HttpJob goes out of scope?
Previously, I would call HttpJob.Release when the activity was closed, in case the user closed the Activity while waiting for a download.
With the HttpJob now declared locally, this is no longer possible.
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
Previously, I would call HttpJob.Release when the activity was closed.
Using wait for you need to Release the job after the wait for.
NOT using wait for you must release it in JobDone.

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

or, using JobDone

B4X:
Sub JobDone (Job As HttpJob)
   Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
   If Job.Success = True Then
      Select Job.JobName
         Case "Job1", "Job2"
            'print the result to the logs
            Log(Job.GetString)
         Case "Job3"
            'show the downloaded image
            Activity.SetBackgroundImage(Job.GetBitmap)
      End Select
   Else
      Log("Error: " & Job.ErrorMessage)
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
   End If
   Job.Release
End Sub
As you can see; It is ALWAYS MANDATORY to release the Job.

Release when the activity was closed.
Sounds like an mistake to me.
 
Last edited:

skaliwag

Member
Licensed User
Longtime User
Yes, I would also put the Job releases where you have them.
The question is, what happens to the Job resources if the user closes an activity while we are waiting for JobDone to complete?
In this case, we would never get to the Job.Release.
This is why I also call Job.Release when the activity is closed.
 

desof

Well-Known Member
Licensed User
Longtime User
Is this available for B4A?
Where do I download an example of this simple?
 

desof

Well-Known Member
Licensed User
Longtime 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

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.

View attachment 55601

What is the correct place to determine if the image is correctly loaded in ImageView1 or ImageView2 and if something fails to be hidden?
 
Status
Not open for further replies.
Top