Android Tutorial HttpUtils - Android web services are now simple!

Status
Not open for further replies.
OkHttpUtils2 is now available. OkHttpUtils2 is an improved version and is recommended for new projects. You shouldn't use HttpUtils (v1)!

HttpUtils is made of a code module and a service module. These two modules make it very simple to download online resources and upload data.

The advantages of using HttpUtils are:
  • Much simpler than working with HttpClient directly.
  • Handles parallel calls efficiently and correctly (protects from RejectedExecutionException exceptions).
  • Downloads are not affected by the activity life cycle.
Using HttpUtils

A simple example of downloading a page and returning the page as string:
B4X:
Sub Globals
 Dim b4a As String
 b4a = "http://www.b4x.com"
End Sub

Sub Activity_Create (FirstTime As Boolean)
 HttpUtils.CallbackActivity = "Main" 'Current activity name.
 HttpUtils.CallbackJobDoneSub = "JobDone"
 HttpUtils.Download("Job1", b4a)
End Sub

Sub JobDone (Job As String)
 Dim s As String
 If HttpUtils.IsSuccess(b4a) Then
  s = HttpUtils.GetString(b4a)
 End If
End Sub
First we configure the callback subs. Then we call HttpUtils.Download or HttpUtils.DownloadList. These calls submit a job request to HttpUtils.
A job is made of one or more links.
HttpUtils raises two types of events while processing a job. The UrlDone event is raised for each successful download with the downloaded url and the JobDone event is raised when the whole job finishes.
You cannot submit a new job while a current job is running (though a job can contain many links).

We have three ways to access a downloaded resource:
  • HttpUtils.GetString(Url As String) - Returns the resource as string
  • HttpUtils.GetBitmap(Url As String) - Returns the resource as bitmap
  • HttpUtils.GetInputStream(Url As String) - Returns an InputStream which allows you to manually read the downloaded resource.
These three methods should only be called after the job is done or inside the UrlDone event sub (for that specific Url).
After downloading a resource the Url serves as the key for that resource.

Inside JobDone event sub you should call HttpUtils.IsSuccess before accessing any Url as it is possible that some or all of the downloads have failed. This is not necessary in UrlDone event as UrlDone is called for each successful download.

Second example:
In this example we first download an image and set it as the activity background. Then we download another 6 Urls and print the last one as string. The code for this example is attached.
B4X:
Sub Process_Globals
    Dim ImageUrl As String
    ImageUrl = "http://www.b4x.com/android/images/logo2.png"
    Dim Job2Links As List
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
    HttpUtils.CallbackActivity = "Main"
    HttpUtils.CallbackJobDoneSub = "JobDone"
    HttpUtils.CallbackUrlDoneSub = "UrlDone"
    Job2Links.Initialize
    Job2Links.AddAll(Array As String( _
        "http://www.google.com", "http://www.yahoo.com", _
        "http://www.bing.com", "http://www.cnn.com", _
        "http://www.twitter.com", "http://www.facebook.com"))
  
    HttpUtils.Download("Job1", ImageUrl)
End Sub

Sub Activity_Resume
    'Check whether a job has finished while the activity was paused.
    If HttpUtils.Complete = True Then JobDone(HttpUtils.Job)
End Sub
Sub UrlDone(Url As String)
    Log(Url & " done")
End Sub
Sub JobDone (Job As String)
    Select Job
        Case "Job1"
            If HttpUtils.IsSuccess(ImageUrl) Then
                Dim b As Bitmap
                b = HttpUtils.GetBitmap(ImageUrl)
                Activity.SetBackgroundImage(b)
            End If
            'Start the second job
            HttpUtils.DownloadList("Job2", Job2Links)
        Case "Job2"
            For i = 0 To HttpUtils.Tasks.Size - 1
                link = HttpUtils.Tasks.Get(i)
                Log(link & ": success=" & HttpUtils.IsSuccess(link))
            Next
            If HttpUtils.IsSuccess("http://www.google.com") Then
                Log(HttpUtils.GetString("http://www.google.com"))
            End If
    End Select
    HttpUtils.Complete = False 'Turn off the complete flag so we won't handle it again if the activity is resumed.
End Sub
What happens when the user presses on the Home key during a download?
The download will complete successfully (we are using a service for this).
However your activity will be paused and the UrlDone and JobDone events will not fire.

When our activity is resumed we should check if we missed anything. This is done with this code:
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
We are calling JobDone ourselves if needed.
In Sub JobDone we reset the Complete flag so we know that this job was handled.
UrlDone event should be considered a "nice to have" feature. Your code should be prepared to handle the case where some UrlDone events were missed due to the activity being paused.

The FlickrViewer example was rewritten and the attached code uses this module.
In this example we first go to the "main" page. In this page we find 9 links to 9 images. We submit a second job with all these links.

We show each image as soon as it is ready by using the UrlDone event.
In JobDone we check if all Urls were handled. We can miss some of these events if the activity was paused during download.

flickr_viewer1.png



HttpUtils, similar to DBUtils, aims to simplify common tasks that many developers face. The code is available for you. So changes can be made as needed.

Updates:

V1.04 - The service is now destroyed when it is no longer needed and recreated when needed again. This version also fixes a bug that caused the application to crash if the service was started after the process was killed.

V1.02 - PostString, PostBytes and PostFile methods added to HttpUtils.
These methods make it easy to post data to a web service (using http POST method).
The behavior of these methods is similar to Download and DownloadList. JobDone event is raised after the response from the server is read.

The latest version (v1.04) is included in HttpUtilsExample.
 

Attachments

  • FlickrViewer.zip
    9.8 KB · Views: 3,377
  • HttpUtilsExample.zip
    7.8 KB · Views: 5,814
Last edited:

pluton

Active Member
Licensed User
Longtime User
This is the problem. Regular global variables are tied to the activity life cycle.
parser should be a process global variable.

Another solution is to remove If FirstTime condition and initialize the parser every time the activity is created.

I have picked the solution N° 2 :sign0156:

I removed If First time condition
Thanks Erel
 

cengolo

Member
Licensed User
Longtime User
problem with httputils

a newbie here.
i tried to run the httputils example. download the file and when i trid to compile, i get the error (in httputils module i think)

Compiling code. Error
Error parsing program.
Error description: Sub is not a valid identifier.

any help will be much appreciated.

cenk
 

pluton

Active Member
Licensed User
Longtime User
a newbie here.
i tried to run the httputils example. download the file and when i trid to compile, i get the error (in httputils module i think)

Compiling code. Error
Error parsing program.
Error description: Sub is not a valid identifier.

any help will be much appreciated.

cenk

I just download it to test it and it is working fine.
Compile OK and started in emulator.
Here is screenshot:

test.png
 

kormos

Member
Licensed User
Longtime User
I would like to have some help about this library. I am an ASP.NET programmer and I have made a web service. I try to use it through basic4android but for some reason I can not make it work. I would like to have some help if it is possible. I want to call a web method using the following parameters:

Web Service URL : http://localhost:999/Contacts.asmx
Web Method : Contacts_Select
Parameter : ContactID

Can someone tell me how to access this web method using a POST request from the web service and store the output of the web method in a string variable.

Thanks in advance.
 

peacemaker

Expert
Licensed User
Longtime User
Erel,

I guess, it's useful, if to make so:

Sub HandleError(TaskId As Int, Reason As String)
Dim link As String
link = TaskToRequest.Get(TaskId)
Log("Error. Url=" & link & " Message=" & Reason)
'Raise URL done event - USEFUL ADDITION, IMHO. Peacemakerv.
If HttpUtils.CallbackUrlDoneSub <> "" Then
CallSub2(HttpUtils.CallbackActivity, HttpUtils.CallbackUrlDoneSub, taskToRequest.Get(TaskId))
End If
End Sub
 

peacemaker

Expert
Licensed User
Longtime User
I see, but:
1) I found that if a notebook with B4A and a running emulator has been hibernated, and later got working again - the emulator has not an internet connection (until restart, maybe another way to restore ?).
And the HTTPUtils service returns "Error. %URL%", but it's just into the log - parent sub that started HTTPUtils - knows nothing about this problem.
Such code addition helps to check each URL and inform the user about it.


2) Second question: sometimes there is a situation when "Already working. Request ignored (%req_name%)" status does not stop at all. For example, if to start HTTPUtils again during XML parsing. It's not correct, yes, but i guess, better to have some finishing, sometime.
 

vukanilod

Member
Licensed User
Longtime User
Is it possible to use httputils to get data from mysql database?
I'm having troubles with ExecuteRemoteQuery because it is working asynchronously so I can't tell if data has been retrieved from my sql or not...

Tnx
 

netchicken

Active Member
Licensed User
Longtime User
I am not too sure what I am doing here, but here goes, :) I am trying to extract the two numbers (92) that come in this line of html code below using Erels example from the first post.

<span itemprop="ratingValue" id="all-critics-meter" class="meter certified numeric ">92</span>

So I made the class

class = "class=" & QUOTE & "meter certified numeric " & QUOTE & ">" 'find the code before the number

and a pattern
pattern = "[0-9][0-9]" 'get the next two numbers after the class code

But it gives an error on the next bit Cannot assign void value. that I suspect shows the pattern isn't matching in lblcode.Text = links.Add(m.Group(1))

(I know that if it loops it will overwrite the lblcode.Text entry but there is only 1 entry in the code with that class.)

B4X:
 If line.IndexOf(class) > -1 Then 'if the class exists
         Dim link As String
         Dim m As Matcher
         m = Regex.Matcher(pattern, line)
         If m.Find Then
         '   links.Add(m.Group(1)) 'add the image link
         lblcode.Text = links.Add(m.Group(1))
         End If

How does it know that the next 2 fields after the class hold the pattern data? It seemed to know that in the example.

Is there a simpler way to extract out the data from between the tags?
<span itemprop="ratingValue" id="all-critics-meter" class="meter certified numeric ">??</span>

Eventually I will need to extract a block of text of indeterminate length from the code that is between

<p id="movieSynopsis" class="movie_synopsis" itemprop="description"> ???? </span>

There must be a simpler way to do it :)

Thanks for your ideas :)
 
Status
Not open for further replies.
Top