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,005
  • HttpUtils2.zip
    8.5 KB · Views: 11,268
Last edited:

Gearcam

Active Member
Licensed User
Longtime User
HI erel

I am trying to implement the JSON from the example

This is the code so far

Dim JSON As JSONParser
Log(Job.GetString)
Dim Map1 As Map
JSON.Initialize(Job.GetString)
Map1 = JSON.NextObject
Dim m As Map 'helper map for navigatingDim MenuItems As List
Dim MenuItems As List
m = Map1.Get("menu")
m = m.Get("popup")
MenuItems = m.Get("menuitem")
For i = 0 To MenuItems.Size - 1
m = MenuItems.Get(i)
Log(m.Get("value"))
Next

i get this error

** Activity (selectaddress) Pause, UserClosed = false **
PackageAdded: package:demita.android
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (selectaddress) Create, isFirst = true **
** Activity (selectaddress) Resume **
** Service (httputils2service) Create **
** Service (httputils2service) Start **
JobName = Job2, Success = true
Job 2
selectaddress_jobdone (java line: 590)
java.lang.RuntimeException: JSON Object expected.
at anywheresoftware.b4a.objects.collections.JSONParser.NextObject(JSONParser.java:47)
at demita.android.selectaddress._jobdone(selectaddress.java:590)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
at anywheresoftware.b4a.keywords.Common$4.run(Common.java:879)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4945)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
java.lang.RuntimeException: JSON Object expected.
** Activity (selectaddress) Pause, UserClosed = false **
** Activity (selectaddress) Resume **
** Activity (selectaddress) Pause, UserClosed = false **
** Activity (selectaddress) Resume **
** Activity (selectaddress) Pause, UserClosed = false **
** Activity (selectaddress) Resume **
** Activity (selectaddress) Pause, UserClosed = false **
** Activity (selectaddress) Resume **
** Activity (selectaddress) Pause, UserClosed = false **


i think its to do with JSON.Initialize(Job.GetString)
this code is in my Sub JobDone (Job As HttpJob) sub and job.getstring holds the data from the SQL search

Steve
 

Gearcam

Active Member
Licensed User
Longtime User
Erel

This is the start of the log
[{"EDEmailHouseCode......

So it is an array

i tried Map1 = JSON.Nextarray

this error
** Activity (selectaddress) Resume **
** Activity (selectaddress) Pause, UserClosed = false **
PackageAdded: package:demita.android
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (selectaddress) Create, isFirst = true **
** Activity (selectaddress) Resume **
** Service (httputils2service) Create **
** Service (httputils2service) Start **
JobName = Job2, Success = true
Job 2
[{"EDEmailHouseCode":"AIRFY4",................}]
selectaddress_jobdone (java line: 590)
java.lang.ClassCastException: java.util.ArrayList cannot be cast to anywheresoftware.b4a.objects.collections.Map$MyMap
at demita.android.selectaddress._jobdone(selectaddress.java:590)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
at anywheresoftware.b4a.keywords.Common$4.run(Common.java:879)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4945)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
java.lang.ClassCastException: java.util.ArrayList cannot be cast to anywheresoftware.b4a.objects.collections.Map$MyMap
 

Gearcam

Active Member
Licensed User
Longtime User
Thanks erel i think i have it working need to test it now.

one other problrm i have is searching on partial matches i use this code to find the data

job1.PostString(ServerUrl, "SELECT XX, YY, ZZ FROM DMSEmailDetails where XX LIKE'" & searchstr & "'")

Which is fine if XX =searchstr completley

how do i code it if i want a partial string like *cat* ie is cat somewhere within XX

I have used this before in access but it does not work in b4a
job1.PostString(ServerUrl, "SELECT XX, YY, ZZ FROM DMSEmailDetails where XX LIKE'*" & searchstr & "*'")



Solved use % not *

thanks for all you help erel

Now the next bit wrighting data to the sql and examples of this anywhere ?
update exiting recod and add new record

Steve
 
Last edited:

CharlesIPTI

Active Member
Licensed User
Longtime User
HttpUtils2

Charles, my answer was related to HttpUtils2 not HttpUtils. I recommend you to use only one of the frameworks in your project.

I'm sorry Did I mistakenly refer to HttpUtils2 without the numeral appended to it once in that previous post?

Because the attached sample project is assuredly attempting HttpUtils2
 

Gearcam

Active Member
Licensed User
Longtime User
upload data to MS SQL database

ok guys so i acn down load data to my app and use it all very good.

But how do you uplaod dat to existing databse ??

Steve
 

Gravy Jones

Member
Licensed User
Longtime User
Great and in the Enterprise now...

Thanks Erel, My management heard that I did some Android development, thanks to B4A. I'm a C++ programmer by day.... They asked if I could build a mobile app that queried a SOAP server and presented the result. I was able to leverage the HttpUtils2 project along with the SaxParser object and quickly create a form based application for my managers phone. He is duly impressed and I owe it all to B4A. It would not surprise me if the company I work for purchases an Enterprise license to use B4A.
 

salmander

Active Member
Licensed User
Longtime User
What does this error means?
B4X:
httpjob_getinputstream (B4A line: 124)


in = File.OpenInput(HttpUtils2Service.TempFolder, taskId)



java.io.FileNotFoundException: /data/data/com.home.cafiq.test/cache/5: open failed: ENOENT (No such file or directory)
   at libcore.io.IoBridge.open(IoBridge.java:406)
   at java.io.FileInputStream.<init>(FileInputStream.java:78)
   at anywheresoftware.b4a.objects.streams.File.OpenInput(File.java:197)
   at com.home.cafiq.test.httpjob._getinputstream(httpjob.java:228)
   at com.home.cafiq.test.search._operationlistjob(search.java:4613)
   at com.home.cafiq.test.search._jobdone(search.java:3749)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
   at anywheresoftware.b4a.keywords.Common$4.run(Common.java:881)
   at android.os.Handler.handleCallback(Handler.java:605)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4424)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
   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:390)
   ... 18 more
java.io.FileNotFoundException: /data/data/com.home.cafiq.test/cache/5: open failed: ENOENT (No such file or directory)
 

CharlesIPTI

Active Member
Licensed User
Longtime User
Synchronous Asynchronous or just plain Krazy ? !

I don't have a GOOD concrete example but could someone please attempt to educate me ... :sign0163:

With this CallSubDelayed method now in HttpUtils2 I find that the tasks (calls) are going by so swiftly that method calls I have blocked out in my Activity create by boolean flags are actually being called before the boolean flags have been set to allow entry into the code portion of Activity_Create that invokes the Calls to HttpUtil2..

How do I adequately describe this...

This isnt the offending section but it will adequately assist my description..
theres a code section ( most of these examples are in activity_Create ) above this first example that fills a list from repeated calls to a HttpUtil2's call to a web service. As you all know this lands in job_done and the job_Done sub calls a related XML Sax parser to truly fill my list object. ( you you guessed it a Global Uggg) :eek:

I had to introduce this counter because the boolean flag was being set before the list was completely filled .. allowing entry into the UI creation portion which you can imagine is a NIGHTMARE... views atop views atop more views. all now mis labled and chaos-'ed up .... in another section [My current concern] I had to create a Map and throw id's into the Map and check if they were there already to prevent their re creation from the redundant Perhaps too fast re entry into a call to the HttpUtil2 to again fill some list...

C'mon people help me out here.. I honestly understand async & sync. I understand polling and callbacks but this is killing me forcing me to write code I'm assuredly not fond of let alone proud of.. for a RAD tool Rapid application development - Wikipedia, the free encyclopedia its becoming quite laborious and frustrating. Assuredly this could be my lack of understanding some basic concept in this use of the tool and its add ons..(HttpUtils2) Please advise ASAP!!!! :sign0085: :sign0104:

B4X:
#Region----------------------{ User Interface creation }--------------------------
'-----------{ xyz }-  ----Left   Top   Width   Height-------   ' 1280 x 800Reference


   If  bBeginUiCreation Then                   
            subSpecificCounter = subSpecificCounter + 1   
            
                     If subSpecificCounter < 2 Then    
                     
         '                  Msgbox("Number of Loops Through UI Creation Block: " & subSpecificCounter, "COUNT UI Loops ")
         '                  If bPreventReCleanUI = False Then
         '                     CleanHouse
         '                     End If
         '                  

                     #Region---------------------{  Create header }--------------------
                                          
                                          
                                          bPreventReCleanUI = True
                                          panHeader.Initialize("")      
                                          panHeader = uiLogic.InitHeaderBlock(panHeader)      
                                          Activity.AddView(panHeader,0%x,0%y,1280dip,80dip)

                     #End Region


B4X:
'#3    Get Order Assignments If MapList has been obtained 
                  If mapLocList.Size > 1  AND bOrderAssignmentListCreated = False Then                                                                                                               
                     FetchOrderAssignments    ' Fills lstOrderAssignments sets flag 'CallToHttpUtil2 inside of this method
                     mapDuplicatePrevention.Initialize
                  End If 
'

B4X:
#Region ---------------------------{   OrderAssignments  EXIST  }----------------------


         If bOrderAssignmentListCreated AND iOrdAssignmentListSize > 0 Then        'OAssignment list created and OAList has content / Count                 
               
               If bOrderAssignmentsToMainLst = False Then                                                         'Process of adding assignments to MAIN Source List hasnt been completed                                                                                                  
               
                        
                        AssimilateOrderAssignments   'CallToHttpUtil2 inside of method that this calls

                  
                  
                  'bOrderAssignmentsToMainLst = true its been completed                                  
              Else                                                         
                  If iRemainderBins >  0 Then                                                                                         'slots remain for scan based acquisition                                                                                           
                           If bMapLocScanCompleted = False Then                                                      ' Force ScanCurrentLoc to Fill Remining Bins                                          
                                 Activity.LoadLayout("lo_ScanLocation")                                                   
                                 Return ' Break out of this                                                                                              
                           End If
                                          ' next loop when bMapLocScanCompleted = true
                           If  bLocationScanValidated = False Then
                               ValidateScannedMapLocation  'CallToHttpUtil2
                           End If                                                                                                    
                                       ' next loop when bLocationScanValidated = true
                           If bMapLocOrderListCreated = False Then                                                   ' Boolean Toggle True When iRemainderBins decremented to 0                                                                                 AssimililateOrders 'CallToHttpUtil2 inside of method that this calls
                                                                                 'GetNext Order & Assign Order to Cart --> into recall Activity_Create(False)
                           End If
                  Else
                           bMapLocOrderListCreated = True
                           bBeginUiCreation = True
                        'CalculateNextAvailablePosition
                  End If                                                                                                                  
            End If
         End If
#End Region

B4X:
Sub AssimilateOrderAssignments


'bins to create = Max - SizeOf OAlst


      If iOrdAssignmentListSize <= MAX_BIN_COUNT Then         
         iRemainderBins = MAX_BIN_COUNT - iOrdAssignmentListSize
      End If 
                                                                                                                  
   If iordAssignmentsToMainListCounter < MAX_BIN_COUNT Then
   
            If iordAssignmentsToMainListCounter < iOrdAssignmentListSize      Then   
               
               lclOrdAssign = lstOrderAssignments.Get(iordAssignmentsToMainListCounter)               
               m_CartPosition = lclOrdAssign.pos      
               
               m_cartState.orderID = lclOrdAssign.ordId    

               If mapDuplicatePrevention.ContainsKey(lclOrdAssign.ordId) = False Then
                     mapDuplicatePrevention.Put(lclOrdAssign.ordId,lclOrdAssign)                     
                                                                                                                           'Msgbox("OrderId Sent To Method: " &    m_cartState.orderID , "FetchOrderByID")                        
               FetchOrderByID  'CallToHttpUtil2 looped - JobDone calls Activity_Create
               Else 
               ' DO NOTHING  Assuredly not add the Duplicate 
               Msgbox("Preventing Duplication : " & m_cartState.orderID, "FetchOrderByID")
               End If
               
               'DoEvents
                              
            End If
   Else   
         If iordAssignmentsToMainListCounter = MAX_BIN_COUNT Then
               bBeginUiCreation = True               
         End If
   End If   

   End Sub




Check this out,,,,,, that last call to FetchOrderByID returns and calls itself again with the same ID before its Job Done can complete...heck even before job done is called
for earlier tasks not to mention even before job done is called using the first orderId, its already trying to do it again with the same orderid which if I recall correctly is called by a counter / incrementer----> List.Get(counter/incrementer) which is incremented when the results are added to the list ... Yea I checked the incrementeer is in the job_done versus the parser not like it mattered where I placed it
 
Last edited:

metrick

Active Member
Licensed User
Longtime User
I got following error when compiling:
Compiling code. Error
Error compiling program.
Error description: Unknown member: success
Occurred on line: 148
If Job.Success = True Then
Word: success

Sample from Erel is working fine.
I have also moved the codes to main module and still get the same error above.
 

metrick

Active Member
Licensed User
Longtime User
Erel, I cannot send the zip file because the file is 2.7 Mb, I will try to reduce the code and send it later.
 

ClRocco

New Member
Licensed User
Longtime User
How to do it?

Hi, I'm new programmer.
I wonder if there is a way to fill a field on a webpage and receive the response of the new page?
Ex: A search on GOOGLE.

I did this using the library Selenium in JAVA.

Thank you.
 
Last edited:
Top