Android Question Synchronous web service call

LoZio

Member
Licensed User
Longtime User
Hi any,
I looked at all the examples regarding calls to web services. All of them are based on "start a call / have a sub async receive the result". This may be useful and I understand why, but is there a way to do a **sync** web service call? I need to wait for a response to decide what to do.
I am in a service module and need to upload data clearing a local queue, so i need to loop
- call ws to upload data
- wait for response
- if ok dequeue and step to the next

Thanks
 

gjt

Member
Licensed User
Longtime User
Maybe use a async call and in JobDone get your result and trigger what else needs to be done?
 
Upvote 0

LoZio

Member
Licensed User
Longtime User
This is a very bad adaptation of the logic that must be implemented. I basically need to loop through a list and send the next item once the preceeding has gone. If in the loop I send element 1 in an async way I find myself sending element 2 before the preceeding call has completed. If I have 100 elements in the list, I have 100 outstanding web service calls in parallel and none of them will succeed.
I can think of some semaphore to fail calls if one is still running, but it's a very very very very poor solution. In regard of this, I see that HttpClient can return false, it seems when another call is already ongoing. Is there some clear documentation about this? I only find half backed examples...
Thanks
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
I can suggest a crude solution but it should work.

(Pseudo - code)

For J = 0 to Jobcount-1
mJobCompleted = false - mJobCompleted is a global var
StartJob
do until mJobCompleted
DoEvents
loop
next

sub jobdone
mJobCompleted = true
end sub

Ciao Zio :)
 
Upvote 0

LoZio

Member
Licensed User
Longtime User
=:)
The do-until loop if full CPU busy waiting, that will kill the battey in minutes. This is exactly what I was trying to avoid.
Waiting for a web service to complete instead is no problem cpu-wise and conserve the battery
 
Upvote 0

LoZio

Member
Licensed User
Longtime User
The hard part is to find the correct logic to delay the call.
The problem I'm solving *IS* synchronous, so there is no async way to do it in an intelligent way.
Creating an async procedure to mimic a sync one basically is a nonsense. I can't really believe there is no way to do a thing that is a basic in any programming language.
Creating a lock in an async code to make it sync is ugly...
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
The DoEvents loop will not work.

You should use HttpUtils2. Create a list with the jobs you want to downloads. Then download the first one.

In JobDone, remove the first item from the list and submit the next job - List.Get(0).

It is not possible in Android to make synchronous network requests. The main thread will be blocked and Android will kill the app after 5 seconds (ANR dialog).
 
Upvote 0

LoZio

Member
Licensed User
Longtime User
The DoEvents loop will not work.

You should use HttpUtils2. Create a list with the jobs you want to downloads. Then download the first one.

In JobDone, remove the first item from the list and submit the next job - List.Get(0).

It is not possible in Android to make synchronous network requests. The main thread will be blocked and Android will kill the app after 5 seconds (ANR dialog).

I have to call web services not download files. Timings and app logic for those two cases are pretty different. Also my list can potentially contain thousands of elements so creating a list ca be pretty memory intensive. I'm rewriting my queue logic to adapt to this but I think it is a weird way to manage things. I'm working in a service so no UI interface thread blocking here.
Also, generally speaking, I can can create a separate thread and put blocking stuff in it, maintaining a straightforward logic in it, without bothering the main UI thread. There's a doc by agraham about spawning threads other than the UI one, this is the normal ( and documented http://developer.android.com/guide/components/processes-and-threads.html) way to code.

Also you may clarify the working of httpclient. When using .execute() I can get back "false", seemingly when the component has a pending job.
If I understand this (cannot find a clear doc about, only examples) if a start a loop around my httpclient.execute this will happen:
1) first time the call is started, and will take some
2) the code returns (no FALSE)
3) The loop is again at the execute() call. The preceding call is still outstanding, so I get back a FALSE and the call does not go on the net

If this is right, looping onto .execute() calls will only start the first call, the loop is much faster than the web service to execute, so all the calls from the second will return false and do nothing. This will be similar so "sync" logic, but will completely kill the battery.

Basically the loop:
- read my local data
- call web service to upload
- loop again

will finally be something like

+ create a sub to read next element to upload

use httputils2 to upload the first one
in JobDone
- de-queue the element
- check if queue is >0
- use httputils2 to upload

All this to replace a while loop...
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Job.Download = a simple GET request.

There is no need to use HttpClient. It will be much simpler to use HttpUtils2. Creating a list with several thousands of elements will not be memory intensive (assuming that you are not loading huge resources such as bitmaps).

HttpClient.Execute returns false if there is already a request pending with the same task id.

HttpClient library was built to efficiently handle many concurrent requests. It allows you, the developer, to focus on the logic instead of dealing with all kinds of threading issues.

Do you really want to send the requests one by one? It can take more than a hour to finish assuming that you have several thousands of requests to make.

There's a doc by agraham about spawning threads other than the UI one, this is the normal ( and documented http://developer.android.com/guide/components/processes-and-threads.html) way to code.
Not sure what you mean with normal way to code. Under the hood Basic4android takes care of the threading issues for you. You should use the "normal" B4A way to code when you develop with B4A ;)
 
Upvote 0

LoZio

Member
Licensed User
Longtime User
Erel I get you point. B4a style async calling surely adapts to some environments, but hardly Is the way to go each time. When I have 1000 data set to upload, spawning them in parallel will crash the client, the server and rarely completes. So after consuming battery and data I have no useful work done.
I'm just saying this can be useful or a disaster, depending on conditions. And forcing to use only one way of coding may put you on the disaster side.
I'll develop my beta using async-loop-unrolling, then will develop a library to cope with the problem.
Is the access to process variables thread safe? I mean putting some variable manipulation in job-done to keep the number of outstanding jobs.
Thanks
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
It will not crash the client. It will also not crash the server because of an internal protection in HttpClient that limits the number of concurrent tasks to the same host to 5. However I agree that it is better to limit the concurrent number of requests in your code. It should be quite simple to do it with HttpUtils2.

Just start five jobs and then whenever a job completes you should send the next job.

Process variables are regular variables.
 
Upvote 0

LoZio

Member
Licensed User
Longtime User
Nice to know about the 5 requests per host, that alone will simplify the things. I will code a general implemetation so setting the parallel level to 1 will be "my" bahavior, plevel>2 and <=5 will parallelize it.
I understand process variables ar regular ones, but I was thinking about which thread runs the JobDone. If it is the only one, then I assume I can safely implement
--
start new job
curjobs=curjobs+1
--
and JobDone end with
---
curjobs=curjobs-1
---

to have curjobs correctly reflecting the number of oustanding jobs.
Thanks
 
Upvote 0
Top