Android Question [B4X] OkHttpUtils2 download time

luke2012

Well-Known Member
Licensed User
Longtime User
Hi all,
I implemented a B4X app that use [B4X] OkHttpUtils2 framework (from @Erel) to download a json.
It is called repeatedly within a for each loop and all works well but the problem is the total download time.

THE PROBLEM
Each download takes 600ms and to populate all the items within my custom list view I need to call the method ".download" n times.
For example it is called 14 times to add 14 items to my clv. So 600ms x 14 = 8400ms = 8,4s
When the user touch the button he have to wait 8 / 9 seconds before the clv will be displayed.
During the app test more than one user is telling me: "nice app but it is too slow".

THE SOLUTION (that I trying)
Talking about B4A App version, while the user is watching the B4X splash screen (I set the splash sleep to 6 seconds) I do the download within the starter service, so when the user touch the button to open the clv, it is mostly populated and he don't have to wait much time.
So the good is that I do the long download only one time and than I cache the data within a runtime cache (using maps).
The bad is if the average time is 500 / 600ms for each download (get), the more the number of items increases, the more the total waiting time for the download (600ms x 14 items, 600ms x 18 items, and so on).

About this solution my questions are:

1) Are there any other alternative solutions ?
2) If this is the only solution, how to do this within the B4i version where the starter service doesn't exist ?

Thanks in advance for your help.
Luca.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
1) Are there any other alternative solutions ?
The problem is not in OkHttp / OkHttpUtils2. There is no faster way to make downloads in Android. The time it takes is related to your server and internet connection.

Don't implement the logic of a cross platform solution in the starter service. Add another class that will be created from the starter service in B4A and from Application_Start in B4i.

Do whatever you need inside this class.
Search for B4XPages.GlobalContext. It can be useful in this case.
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
The problem is not in OkHttp / OkHttpUtils2. There is no faster way to make downloads in Android. The time it takes is related to your server and internet connection.

Don't implement the logic of a cross platform solution in the starter service. Add another class that will be created from the starter service in B4A and from Application_Start in B4i.

Do whatever you need inside this class.
Search for B4XPages.GlobalContext. It can be useful in this case.

Thank you for your reply.
1) "The problem is not in OkHttp / OkHttpUtils2. There is no faster way to make downloads in Android. The time it takes is related to your server and internet connection.": Yes I known.

2) "Add another class that will be created from the starter service in B4A and from Application_Start in B4i." ---> OK.
 
Upvote 0

josejad

Expert
Licensed User
Longtime User
For example it is called 14 times to add 14 items to my clv.
Probably you’re doing that way due to that’s the way the data are structured but... is there no way of getting all data at a time? Not a database or a service can give you the json with all the data?
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
Probably you’re doing that way due to that’s the way the data are structured but... is there no way of getting all data at a time? Not a database or a service can give you the json with all the data?

Hi @José J. Aguilar.
The server is a drupal server and I'm using drupal json api to access the data.
I state that I do not know the drupal bees well and studying a tutorial on drupal for a moment I understood how to download the single nodes.

For example, I need to download JSON for drupal nodes: 32, 33, 34, 35, 36, 37, 38, 41
To do this, actually within the app I'm using this calls using .download method:

and so on....

So the total download time is: 600ms x 8 (.download calls).

In this case I have to call 8 times .download method to have all the nodes data.
I don't known if there is another api that can return all the above nodes using one call.
I known that there are some drupal api that allow you to download all the nodes that match as specific type. For example "article". But in this case I don't want to download alla the nodes but only 8 specific nodes.
 
Last edited:
Upvote 0

josejad

Expert
Licensed User
Longtime User
Hi luke2012.

Sorry, I haven't used drupal, but I think the best way to improve your app is searching how to get multiples nodes at once, and then populate you xCLV. Maybe someone here knows drupal, or probably you can get some answers in a drupal forum.
You probably have done some google searching, maybe these ones can help you... it seems you need to create a views REST export

 
Upvote 0

rraswisak

Active Member
Licensed User
Longtime User
@luke2012 since you don't provide the code how you download the json, my comment maybe insufficient with your need,

What i'm thinking, you have to create separate sub to download the json and call it with nodes as parameter.

B4X:
Sub Main
    Dim nodes() As Int = Array ( 32, 33, 34, 35, 36, 37, 38, 41 )
    For i=0 To nodes.size -1
        DownloadJSON(nodes(i))
    Next
End Sub

Sub DownloadJSON(node As Int)
    Dim url As String = $"https://hostname.com/node/${node}?_format=json"$
    Dim job As HttpJob
    job.Initialize("",Me)
    job.Download(url)
    Wait For (job) JobDone (j As HttpJob)
    If j.Success Then
        '...
    Else
        '...
    End If
    job.Release
End Sub
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
@luke2012 since you don't provide the code how you download the json, my comment maybe insufficient with your need,

What i'm thinking, you have to create separate sub to download the json and call it with nodes as parameter.

B4X:
Sub Main
    Dim nodes() As Int = Array ( 32, 33, 34, 35, 36, 37, 38, 41 )
    For i=0 To nodes.size -1
        DownloadJSON(nodes(i))
    Next
End Sub

Sub DownloadJSON(node As Int)
    Dim url As String = $"https://hostname.com/node/${node}?_format=json"$
    Dim job As HttpJob
    job.Initialize("",Me)
    job.Download(url)
    Wait For (job) JobDone (j As HttpJob)
    If j.Success Then
        '...
    Else
        '...
    End If
    job.Release
End Sub

Hi @rraswisak. Thanks for your reply.
This is the same thing that I'm doing within my app code.
The point is that for each:

B4X:
   job.Download(url)
   Wait For (job) JobDone (j As HttpJob)
......

The time is about 500 / 600ms (this is not a time that is related to network and server time).
The for statement repeat this call 8 times so the total time is "many" seconds from a user perspective (I mean the time that a user have to wait in order to see the result).

For this I found I workaround. Run this (download) code while the user is watching the app splash.
In this way when the user touch the button to see the xCLV much of all data has been downloaded and saved in the app cache and the wait time (to see the xCLV populated) is near 0.

I known that this is not the best solution but is the simplest and in this case it works.
The point is to find a way to ask to drupal apis to return the notes data ( 32, 33, 34, 35, 36, 37, 38, 41) using one single call (.download).
In this case you have only the network latency and the server latency (time) only for a single download not for a sum of 8 downloads.

Probably, I have to understand how to do this with the drupal community (from api server side).
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
The problem is not in OkHttp / OkHttpUtils2. There is no faster way to make downloads in Android. The time it takes is related to your server and internet connection.

Don't implement the logic of a cross platform solution in the starter service. Add another class that will be created from the starter service in B4A and from Application_Start in B4i.

Do whatever you need inside this class.
Search for B4XPages.GlobalContext. It can be useful in this case.

I followed your advice and implemented everything within a class.
Another thing... Before this, I ran this code within a button _Click event like the @rraswisak code example:

B4X:
Sub Button1_Click
     B4XLoadingIndicator1.Show

    Dim nodes() As Int = Array ( 32, 33, 34, 35, 36, 37, 38, 41 )
    For i=0 To nodes.size -1
        DownloadJSON(nodes(i))
    Next

    B4XLoadingIndicator1.Hide
End Sub

Sub DownloadJSON(node As Int)
    Dim url As String = $"https://hostname.com/node/${node}?_format=json"$
    Dim job As HttpJob
    job.Initialize("",Me)
    job.Download(url)
    Wait For (job) JobDone (j As HttpJob)
    If j.Success Then
        '...
    Else
        '...
    End If
    job.Release
End Sub

Actually the _click code is changed like this:

B4X:
Sub Button1_Click

    'if data donwload is completed then the I populate and show the xCLV
    'AppGlobals is the class where the DownloadJSON code run
    'DataLoadDone1 is the flag that I have to check to known if the download has been completed

    If AppGlobals.DataLoadDone1 Then
        B4XPages.ShowPage("subcats")
        SubCatsPage.LoadSubCatList (AppGlobals.MAIN_CAT1_NAME) '---> this is the sub that populate the xCLV
    Else
        toast.Show(Application.LabelName & ": I am uploading the data. Please try again in a moment...")
    End If

End Sub

Instead of a toast msg I wish to show the B4XLoadingIndicator while the DataLoadDone1 flag is false and hide it when DataLoadDone1 is true. Which is the correct way to do this ? wait for ? do loop ?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Show the indicator. Call the sub with Wait For and then hide the indicator.

 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
Show the indicator. Call the sub with Wait For and then hide the indicator.


Thanks for your suggestion, but the sub is called within the class initialize and the class is initiliazed by the starter service.
The sub should run at app startup (starter) and I need to call it only one time because all the downloaded data (api calls) will be cached and I don't need to call the download sub within the Button1_Click.
 
Last edited:
Upvote 0
Top