Android Tutorial HttpUtils2 - Web services are now even simpler

Erel

Administrator
Staff member
Licensed User
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.basic4ppc.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.basic4ppc.com/print.php", "first key=first value&key2=value2")

   'Send a GET request
   job3.Initialize("Job3", Me)
   job3.Download("http://www.basic4ppc.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:



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

Last edited:

PHB2

Member
Licensed User
Do we still need this code Erel:

B4X:
Sub Activity_Resume
    'Check whether a job has finished while the activity was paused.
    If HttpUtils.Complete = True Then JobDone(HttpUtils.Job)
End Sub
I had this in place when I used the original HttpUtils code.
 

Erel

Administrator
Staff member
Licensed User
No. It is not required as CallSubDelayed takes care of this internally.
 

salmander

Active Member
Licensed User
Hi Erel,

I am using HttpUtils2 in PushService to download the data.

but it is giving me Null Pointer exception. here is the error
B4X:
httpjob_download2 (java line: 132)

java.lang.NullPointerException
   at com.home.cafiq.test.httpjob._download2(httpjob.java:132)
   at com.home.cafiq.test.pushservice._gettext(pushservice.java:218)
   at com.home.cafiq.test.pushservice._messagearrived(pushservice.java:454)
   at com.home.cafiq.test.pushservice._service_start(pushservice.java:1285)
   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.BA.raiseEvent(BA.java:154)
   at com.home.cafiq.test.pushservice.handleStart(pushservice.java:61)
   at com.home.cafiq.test.pushservice.onStartCommand(pushservice.java:46)
   at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
   at android.app.ActivityThread.access$1900(ActivityThread.java:123)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   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)
java.lang.RuntimeException: Unable to start service com.home.cafiq.test.pushservice@41119638 with Intent { cmp=com.home.cafiq.test/.pushservice (has extras) }: java.lang.RuntimeException: java.lang.NullPointerException


   at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2376)
   at android.app.ActivityThread.access$1900(ActivityThread.java:123)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   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)
Any ideas of the cause? and how to rectify it please?

Edit:
My push service receives the push notification fine. In my push service, I am downloading additional data from the server using the HttpUtils2 method. But the application is crashing and error logs is giving the above error message.
 
Last edited:

Erel

Administrator
Staff member
Licensed User
Can you post the service code?

Also, you should run your code with the debugger to see the exact error line.
 

salmander

Active Member
Licensed User
I tried running the code in debugger mode, the app pauses at line 81 of HttpJob of the httputils2 for a second and then the app just crashes. The sub JobDone never gets executed.
B4X:
        ' line 81 of HttpJob module.
   CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)
Here is the related service code of PushService (service module).
B4X:
Sub MessageArrived (Intent As Intent)
   Dim From, CollapseKey, Data As String
   If Intent.HasExtra("from") Then From = Intent.GetExtra("from")
   If Intent.HasExtra("data") Then Data = Intent.GetExtra("data")
   If Intent.HasExtra("collapse_key") Then CollapseKey = Intent.GetExtra("collapse_key")

   'Here you should handle the new message:
   Log("New message arrived: " & Data)
   Log("From: " & From)
   Log("CollapseKey: " & CollapseKey)
   Log("Data: " & Data)
   'ToastMessageShow("New message: " & Data, True)
   
   ' Process the message now, calling sub
   getText(Data)
   
End Sub

Sub getText(id As String)
   Log("getText sub initiated")
   'fetch message url
   Dim url As String
   url = "https://" ' https url to get the message details
   'fetchTextHC.Initialize("fetchTextHC")
   'Dim req As HttpRequest
   Log("fetchMessage URL: " & url & "id=" & id)
   'req.InitializeGet(url & "id=" & id)
   'fetchTextHC.Execute(req, 1)
   job1.Initialize("getText", Me)
   job1.Download2(url, Array As String("id", id))
   
End Sub
 

Erel

Administrator
Staff member
Licensed User
Can you post the error message from the logs?

Note that the Url is broken. It is missing the host part.
 

salmander

Active Member
Licensed User
Erel URL is not broken. I removed it as its my company server address.
B4X:
** Service (pushservice) Start **


servicestarted
New message arrived: 322
From: '<gmail_id hidden>
CollapseKey: collapse_key1
Data: 322
getText sub initiated


fetchMessage URL: <URL>


httpjob_download2 (B4A line: 81)


CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)



java.lang.NullPointerException
   at com.home.cafiq.test.httpjob._download2(httpjob.java:180)
   at com.home.cafiq.test.pushservice._gettext(pushservice.java:295)
   at com.home.cafiq.test.pushservice._messagearrived(pushservice.java:701)
   at com.home.cafiq.test.pushservice._service_start(pushservice.java:1981)
   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.BA.raiseEvent(BA.java:154)
   at com.home.cafiq.test.pushservice.handleStart(pushservice.java:61)
   at com.home.cafiq.test.pushservice.onStartCommand(pushservice.java:46)
   at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
   at android.app.ActivityThread.access$1900(ActivityThread.java:123)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   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)
java.lang.RuntimeException: Unable to start service com.home.cafiq.test.pushservice@411720b8 with Intent { cmp=com.home.cafiq.test/.pushservice (has extras) }: java.lang.RuntimeException: java.lang.NullPointerException
   at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2376)
   at android.app.ActivityThread.access$1900(ActivityThread.java:123)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   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: java.lang.RuntimeException: java.lang.NullPointerException
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:199)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:154)
   at com.home.cafiq.test.pushservice.handleStart(pushservice.java:61)
   at com.home.cafiq.test.pushservice.onStartCommand(pushservice.java:46)
   at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
   ... 10 more
Caused by: java.lang.NullPointerException
   at com.home.cafiq.test.httpjob._download2(httpjob.java:180)
   at com.home.cafiq.test.pushservice._gettext(pushservice.java:295)
   at com.home.cafiq.test.pushservice._messagearrived(pushservice.java:701)
   at com.home.cafiq.test.pushservice._service_start(pushservice.java:1981)
   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)
   ... 14 more
 

Erel

Administrator
Staff member
Licensed User
Yes. It is a bug.

I plan to release v2.02 in a few days that will fix this issue and some others. You can already download v2.01 (considered a beta version) which should fix this issue. It is available in the same link as before. The file name is beta.exe instead of b4a-full.exe.

I would be happy to hear your results...
 

doomer

Member
Licensed User
Simple autenticate

Hi i try to login to a basic login .htaccess file protection

i set job1.username and password

how to use the job1.download command with login



greets doomer
 

Roger Garstang

Well-Known Member
Licensed User
Downloaded both of these but haven't really had a chance to use them yet. The example above for POST and GET seem backwards though. The URL Encoded way you send the POST would work better for GET and an Array or Map way would work better for POST. POST would work best sent as multipart/form-data instead of url encoded like GET then you can send binary files, images, etc.
 

Erel

Administrator
Staff member
Licensed User
@doomer,
You should just set the UserName and Password:
B4X:
job3.Initialize("Job3", Me)
job3.Username = "xxx"
job3.Password = "yyy"
job3.Download("http://www.example.com")
@Roger, only the GET parameters need to be url encoded. It is a good idea to add an option for multipart/form-data.
 

doomer

Member
Licensed User
it works next question: How to save file ?

when i download a file wit

jonb1.dowload(filurl)

how to save

this is done with httputil the old one

File.Copy2(httputil.GetInputStream(FileUrl),File.OpenOutput(File.DirDefaultExternal,"Test.ini",False))


how to do that with httpjob.

greets

Doomer
 
Top