Android Tutorial HttpUtils2 - Web services are now even simpler

HttpUtils2 was replaced with OkHttpUtils2: https://www.b4x.com/android/forum/threads/okhttp-replaces-the-http-library.54723/
Both libraries are included in the IDE.


HttpUtils2 is a small framework that helps with communicating with web services (Http servers).

HttpUtils2 is an improved version of HttpUtils.

The advantages of HttpUtils2 over HttpUtils are:
  • Any number of jobs can run at the same time (each job is made of a single task)
  • Simpler to use
  • Simpler to modify
  • Supports credentials
  • GetString2 for encodings other than UTF8
  • Download2 encodes illegal parameters characters (like spaces)

HttpUtils2 requires Basic4android v2.00 or above.
It is made of two code modules: HttpUtils2Service and HttpJob (class module).
The two code modules are included in HttpUtils2 (attached project).
It depends on the following libraries: Http and StringUtils

How to use
- Dim a HttpJob object
- Initialize the Job and set the module that will handle the JobDone event.
The JobDone event is raised when a job completes.
The module can be an Activity, Service or class instance. You can use the Me keyword to reference the current module.
Note that CallSubDelayed is used to call the event.
- Call one of the following methods:
Download, Download2, PostString, PostBytes or PostFile. See HttpJob comments for more information.
- Handle the JobDone event and call Job.Release when done.
Note that the completion order may be different than the submission order.

To send credentials you should set Job.UserName and Job.Password fields before sending the request.

For example the following code sends three request. Two of the responses will be printed to the logs and the third will be set as the activity background:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim job1, job2, job3 As HttpJob
   job1.Initialize("Job1", Me)

   'Send a GET request
   job1.Download2("http://www.b4x.com/print.php", _
      Array As String("first key", "first value :)", "second key", "value 2"))

   'Send a POST request
   job2.Initialize("Job2", Me)
   job2.PostString("http://www.b4x.com/print.php", "first key=first value&key2=value2")

   'Send a GET request
   job3.Initialize("Job3", Me)
   job3.Download("http://www.b4x.com/forum/images/categories/android.png")
End Sub

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

This example and an example of downloading several images from Flickr are attached:

flickr_viewer1.png


Starting from B4A v2.70, HttpUtils2 is included as a library in the IDE.

Relevant links

ImageDownloader - Service that makes it simple to efficiently download multiple images. Note that a simpler "FlickrViewer example" is available there.
DownloadService - Download files of any size with DownloadService. Includes progress monitoring and the ability to cancel a download.
 

Attachments

  • FlickrViewer.zip
    10.7 KB · Views: 9,188
  • HttpUtils2.zip
    8.5 KB · Views: 11,523
Last edited:

Ed Verstegen

New Member
Licensed User
Longtime User
I am need of some assistance. I am trying to communicate with my raspberry pi webserver via Http. I have successfully done so using the above code and mainly using (job1.PostString("http://IP:5000/onoff2", "") when I do this my server responds with "on" but I cant seem to pull that return into my app that I am creating.


B4X:
Sub JobDone (Job AsHttpJob)
 
  Log("JobName = " & Job.JobName & ", Success = " & Job.Success)
 
  If Job.Success = TrueThen
 
      Select Job.JobName
 
        Case"Job1"
 
            'print the result to the logs
 
            status = Job.GetString
 
      EndSelect
 
  Else
 
      Log("Error: " & Job.ErrorMessage)
 
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
 
  EndIf
 
  Job.Release
 
End Sub
 
 
Sub light1_Click
 
  job1.poststring("http://192.168.1.152:5000/light1on")
 
  Label3.Text = status
 
End Sub
 

appie21

Active Member
Licensed User
Longtime User
Hello
i have vb code and i try it to get work in b4a any tips / help welcome

My code in Vb.net looks like this:

how do it in b4a?

Dim lampstatus As String = "true"


Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
If CheckBox1.Checked = True Then
lampstatus = "true"
Else
lampstatus = "false"

End If

Dim result As String
Dim MyURL As String, postData As String
Dim winHttpReq As Object
winHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")
MyURL = "http://192.168.1.5/api/newdeveloper/lights/" & "1" & "/state"

postData = "{""on"": " & lampstatus & "}"
winHttpReq.Open("PUT", MyURL, False)
winHttpReq.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
winHttpReq.Send(postData)

result = winHttpReq.ResponseText
REM CheckBox1.Text = result
End Sub

very time i get a bad reguest if i do it in b4a

B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

End Sub

Sub Activity_Create(FirstTime As Boolean)
      Dim job1 As HttpJob
  Activity.LoadLayout("Layout1")
  job1.Initialize("Job1", Me)
  job1.Download2("http://192.168.1.5/api/newdeveloper/", _
      Array As String("first key", "first value :)", "second key", "value 2"))
'http://192.168.1.5/api/newdeveloper/lights
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


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

  End Sub

this is the page if i open it
http://192.168.1.5/api/newdeveloper/lights/1

give
{"1":{"name": "Rechts"},"2":{"name": "Links"},"3":{"name": "Boven"}}

here i try a get but give bad request
 
Last edited:

appie21

Active Member
Licensed User
Longtime User
I see :(

but now i want put data to the lights
i found this
http://www.b4x.com/android/forum/threads/httputils2-put.26797/#content

i want to sent'with a PUT {"on":true}
B4X:
Dim aan As String
  Dim lampstatus As String = "true"
  aan = "{""on"": " & lampstatus & "}"
  If Job.Success = True Then
      ToastMessageShow(Job.GetString,True)
Job.PostString("http://192.168.1.5/api/newdeveloper/lights/2/state", aan )
but then i get a error that i can;t post so I must use Put
What is the put command?
 
Last edited:

LaryLee

Member
Licensed User
Longtime User
RedwordError.jpg

I am a beginner for B4A, and need someone colud help me to solve the Red-words error ! what lib should download and copy to which folder ....Thanks ,
 

LaryLee

Member
Licensed User
Longtime User
Starting from B4A v2.7 HttpUtils2 is also included as a library. So you can just check HttpUtils2 in the libraries folder and work with it (make sure to remove the two modules).

If you do want to run the source code then you should add check the following libraries: Http and StringUtils.
Starting from B4A v2.7 HttpUtils2 is also included as a library. So you can just check HttpUtils2 in the libraries folder and work with it (make sure to remove the two modules).

If you do want to run the source code then you should add check the following libraries: Http and StringUtils.


Thanks!:)
 

mhartwig

Member
Licensed User
Longtime User
Does HTTPUtils2 support DELETE and PUT requests?

EDIT: NM Found my answer after sifting through some search results.
 
Last edited:

NeoTechni

Well-Known Member
Licensed User
Longtime User
Despite the download being a success, I am getting:

httpjob_getstring2 (java line: 187)


java.io.FileNotFoundException: /data/data/com.omnicorp.lcarui.test/cache/2: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:409)
at java.io.FileInputStream.<init>(FileInputStream.java:78)
at anywheresoftware.b4a.objects.streams.File.OpenInput(File.java:197)
at com.omnicorp.lcarui.test.httpjob._getstring2(httpjob.java:187)
at com.omnicorp.lcarui.test.httpjob._getstring(httpjob.java:176)
at com.omnicorp.lcarui.test.stimer._jobdone(stimer.java:191)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
at anywheresoftware.b4a.keywords.Common$5.run(Common.java:958)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4998)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
at dalvik.system.NativeStart.main(Native Method)
Caused by: libcore.io.ErrnoException: open failed: ENOENT (No such file or directory)
at libcore.io.Posix.open(Native Method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
at libcore.io.IoBridge.open(IoBridge.java:393)
... 18 more
java.lang.RuntimeException: java.lang.RuntimeException: java.io.FileNotFoundException: /data/data/com.omnicorp.lcarui.test/cache/2: open failed: ENOENT (No such file or directory)
at anywheresoftware.b4a.keywords.Common$5.run(Common.java:961)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4998)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: java.io.FileNotFoundException: /data/data/com.omnicorp.lcarui.test/cache/2: open failed: ENOENT (No such file or directory)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:196)
at anywheresoftware.b4a.keywords.Common$5.run(Common.java:958)
... 9 more
Caused by: java.io.FileNotFoundException: /data/data/com.omnicorp.lcarui.test/cache/2: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:409)
at java.io.FileInputStream.<init>(FileInputStream.java:78)
at anywheresoftware.b4a.objects.streams.File.OpenInput(File.java:197)
at com.omnicorp.lcarui.test.httpjob._getstring2(httpjob.java:187)
at com.omnicorp.lcarui.test.httpjob._getstring(httpjob.java:176)
at com.omnicorp.lcarui.test.stimer._jobdone(stimer.java:191)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
... 10 more
Caused by: libcore.io.ErrnoException: open failed: ENOENT (No such file or directory)
at libcore.io.Posix.open(Native Method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
at libcore.io.IoBridge.open(IoBridge.java:393)
... 18 more

I've altered your code to fail gracefully, but that doesn't solve the problem

B4X:
'Returns the response as a string.
Public Sub GetString2(Encoding As String) As String
    Dim tr As TextReader,res As String
    If File.Exists(HttpUtils2Service.TempFolder, taskId) Then
        tr.Initialize2(File.OpenInput(HttpUtils2Service.TempFolder, taskId), Encoding)
        res = tr.ReadAll
        tr.Close
    Else
        Log("CACHE FILE MISSING")
    End If
    Return res
End Sub

I also get errors if the url contains special characters (space, comma) and have altered your code to compensate

B4X:
'Add dim URL As String to Class_Globals

'Submits a HTTP GET request.
'Consider using Download2 if the parameters should be escaped.
Public Sub Download(Link As String)
    req.InitializeGet(FilterURL(Link))
    CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)
End Sub

Private Sub FilterURL(Link As String) As String
    URL = link.Replace(" ", "%20").Replace(",", "%2C")
    Return URL
End Sub

'Submits a HTTP GET request.
'Encodes illegal parameter characters.
'<code>Example:
'job.Download2("http://www.example.com", _
'    Array As String("key1", "value1", "key2", "value2"))</code>
Public Sub Download2(Link As String, Parameters() As String)
    Dim sb As StringBuilder
    sb.Initialize
    sb.Append(FilterURL(Link))
    If Parameters.Length > 0 Then sb.Append("?")
    Dim su As StringUtils
    For i = 0 To Parameters.Length - 1 Step 2
        If i > 0 Then sb.Append("&")
        sb.Append(su.EncodeUrl(Parameters(i), "UTF8")).Append("=")
        sb.Append(su.EncodeUrl(Parameters(i + 1), "UTF8"))
    Next
    req.InitializeGet(sb.ToString)
    CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)       
End Sub
 

biometrics

Active Member
Licensed User
Longtime User
Hi Erel,

I'm trying to do a POST. Your sample works but if I change the URL to our server it fails. As a simple test I changed it to www.google.com and it still fails.

B4X:
  'Send a POST request
   job2.Initialize("Job2", Me)
   job2.PostString("http://www.google.com", "first key=first value&key2=value2")

The apps dies and the log has this:

(Intent) Intent { act=android.intent.action.MAIN flg=0x20000000 cmp=anywheresoftware.b4a.samples.httputils2/.main }
no extras
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
startService: class anywheresoftware.b4a.samples.httputils2.httputils2service
** Service (httputils2service) Create **
** Service (httputils2service) Start **
An error occurred:
(Line: 36) Return taskCounter
java.lang.ArrayIndexOutOfBoundsException: 3


So looks like it dies in HttpUtils2Service Sub SubmitJob on Return taskCounter.

*****************
EDIT: No worries, I only see now that you are including it as a library and that it doesn't have the same problem.
*****************
 
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
I am sending the following 3 GET REQUESTS. Job 1 and Job 3 returns the correct data (i.e complete message). Job 2 returns some of the data but not all. The list with all the towns/cities are not in the returned data. Can someone please advise

B4X:
    job1.Initialize("Job1", Me)
    job1.Download2("http://southafricanweather.mobi", _
    Array As String("first key", "first value", "second key", "second value"))
    job2.Initialize("Job2", Me) 
    job2.Download2("http://southafricanweather.mobi/city.aspx?province=Eastern%20Cape", _
    Array As String("first key", "first value", "second key", "second value"))
    job3.Initialize("Job3", Me)
    job3.Download2("http://southafricanweather.mobi/weather.aspx?city=Algoapark&province=Eastern%20Cape", _
    Array As String("first key", "first value", "second key", "second value"))
 

Johan Schoeman

Expert
Licensed User
Longtime User
With reference to my posting above and specifically Job2, the code below returns the correct data for Job2. Am I missing some of the interpretation of how to make use of job2.Download2(....... ?????


B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
 
Dim hc As HttpClient
Dim req As HttpRequest
Dim In As InputStream
 
End Sub
 
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
 
Dim Button1 As Button
Dim edtgeo As EditText
 
End Sub
 
Sub Activity_Create(FirstTime As Boolean)
'    If FirstTime Then
'    End If
    Activity.LoadLayout("1")
    hc.Initialize("hc")
 
End Sub
 
Sub Activity_Resume
 
End Sub
 
Sub Activity_Pause (UserClosed As Boolean)
 
End Sub
Sub Button1_Click
 
    Dim townpath As String
    edtgeo.Text = ""
    townpath = "http://southafricanweather.mobi/city.aspx?province=Eastern%20Cape"
    req.InitializeGet(townpath)
    hc.Execute(req, 1)
   
End Sub
Sub hc_ResponseSuccess(Response As HttpResponse, TaskId As Int)
    Response.GetAsynchronously("StrmResponse",File.OpenOutput(File.DirDefaultExternal, "Tempjhs.xml", False), True, TaskId)
End Sub
Sub hc_ResponseError(Response As HttpResponse, Reason As String, StatusCode As Int, TaskId As Int)
    If Response <> Null Then
      Msgbox("Connection Error", "")
      Response.Release
    End If
End Sub
Sub StrmResponse_StreamFinish(Success As Boolean, TaskId As Int)
 
    In = File.OpenInput(File.DirDefaultExternal, "Tempjhs.xml")
    edtgeo.Text= File.ReadString(File.DirDefaultExternal, "Tempjhs.xml")
    In.Close
 
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Am I missing some of the interpretation of how to make use of job2.Download2(....... ?????
Yes. You should either put all the parameters in the URL yourself or put all the parameters in the array.

In this case you should remove ?province... from the URL and add it to the array:
B4X:
Array As String("province", "Eastern Cape", ...)
 

David3333

New Member
Licensed User
Longtime User
Hello,

I'm using job.Download from HTTPUtils2 to download data from a Webservice that I created using VB.NET.

I works just fine, but now i want to add authentication, so I use job.user and job.password.

The question is, from the webservice side how do I access to these parameters?
 

David3333

New Member
Licensed User
Longtime User
You mean to pass the username and password as parameters? Like .../getData?user=username&pass=password ?
 
Top