B4J Question [Solved] Download Files from server with progress

Dadaista

Active Member
Licensed User
Longtime User
Hi all
How can I do something like this
from B4J?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
B4A + B4J solution:
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
End Sub

Public Sub Initialize
  
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
End Sub

Private Sub Button1_Click
 'In B4A you need to add to manifest editor: CreateResourceFromFile(Macro, Core.NetworkClearText)
    Wait For (DownloadAndTrackProgress("http://mirror.filearena.net/pub/speed/SpeedTest_16MB.dat")) Complete (Success As Boolean)
End Sub

Private Sub DownloadAndTrackProgress (url As String) As ResumableSub
    Dim j As HttpJob
    j.Initialize("", Me)
    j.Download(url)
    Wait For (FindTaskId(j)) Complete (TaskId As Int)
    Dim b() As Boolean = Array As Boolean(False)
    TrackProgress(j, b, TaskId)
    Wait For (j) JobDone (j As HttpJob)
    b(0) = True
    j.Release
    Return j.Success
End Sub

Private Sub FindTaskId (job As HttpJob) As ResumableSub
    Do While True
        Sleep(30)
        If HttpUtils2Service.TaskIdToJob.IsInitialized = False Then Continue
        Dim TaskToJob As Map = HttpUtils2Service.TaskIdToJob
        For Each id As Int In TaskToJob.Keys
            If TaskToJob.Get(id) = job Then
                Return id
            End If
        Next
    Loop
    Return -1
End Sub

Private Sub TrackProgress (j As HttpJob, Stop() As Boolean, TaskId As Int)
    Do While Stop(0) = False
        If j.Out.IsInitialized Then
            Dim TotalLength As Long = j.Response.ContentLength
            Dim size As Long = File.Size(HttpUtils2Service.TempFolder, TaskId)
            Log(size & ", " & TotalLength)
        End If
        Sleep(100)
    Loop
End Sub

You need to add to the build configuration (Ctrl + B): HU2_PUBLIC
 
Last edited:
Upvote 0

Dadaista

Active Member
Licensed User
Longtime User
Thank you very much Erel
I am going to try to add to my project.
Where I must add " HU2_PUBLIC"?... My IDE is in spanish... 1st, 2nd or 4th field?...
2021-01-22.png

Must I add something else to
B4X:
#CustomBuildAction: After Packager, C:\Program Files (x86)\Inno Setup 6\.....
 
Upvote 0

Dadaista

Active Member
Licensed User
Longtime User
Hi!
The file is saved correctly. It size is 0k
But, why in this line
B4X:
Log(size & ", " & TotalLength)
Size is always = 0? :rolleyes:
B4X:
0, 16777216
0, 16777216
0, 16777216
0, 16777216
0, 16777216
0, 16777216
0, 16777216
0, 16777216
0, 16777216
How can I solve it?
 
Upvote 0

Dadaista

Active Member
Licensed User
Longtime User
Create a small project where it doesn't work and upload it.

It is amazing. Exactly same subs in both projects and in my project does not work... hahahahahaha???

Well.. in Debug mode does not work but in Release (uploaded project)
 

Attachments

  • ProjectDnT.zip
    2.6 KB · Views: 395
Upvote 0

Dadaista

Active Member
Licensed User
Longtime User
Not in my computer

in debug mode:
B4X:
WARNING: package com.sun.javafx.embed.swing.oldimpl not in javafx.swing
Waiting for debugger to connect...
Program started.
Ha ocurrido un error en la línea: 56 (Main)
java.lang.NullPointerException
    at b4j.example.main$ResumableSub_DownloadAndTrackProgress.resume(main.java:269)
    at b4j.example.main._downloadandtrackprogress(main.java:215)
    at b4j.example.main$ResumableSub_Button1_Click.resume(main.java:162)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resumeAsUserSub(DebugResumableSub.java:47)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:632)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:234)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:91)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:78)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resume(DebugResumableSub.java:42)
    at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:136)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:85)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:78)
    at anywheresoftware.b4a.keywords.Common$3.run(Common.java:1086)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:832)
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I understand. It is related to a bug in debug mode that is already fixed in the unreleased version that I'm using.

Try this:
B4X:
Private Sub DownloadAndTrackProgress (url As String, sFile As String) As ResumableSub
    Dim j As HttpJob
    j.Initialize("", Me)
    j.Download(url)
    #if debug
    'delete if using B4J v9.0+
    Sleep(0)
    #End If
    Dim TaskToJob As Map = HttpUtils2Service.TaskIdToJob
    Do While HttpUtils2Service.TaskIdToJob.IsInitialized = False
        Sleep(30)
    Loop
       
    Dim TaskId As Int
    For Each id As Int In TaskToJob.Keys
        If TaskToJob.Get(id) = j Then
            TaskId = id
            Exit
        End If
    Next
    Dim b() As Boolean = Array As Boolean(False)
    TrackProgress(j, b, TaskId)
    Wait For (j) JobDone (j As HttpJob)
    b(0) = True
   
    If j.Success Then
        Dim out As OutputStream = File.OpenOutput(File.DirTemp, sFile, False)
        File.Copy2(j.GetInputStream, out)
        out.Close '<------ very important
    End If
   
    j.Release
    Return j.Success
End Sub
 
Last edited:
Upvote 0

Dadaista

Active Member
Licensed User
Longtime User
I understand. It is related to a bug in debug mode that is already fixed in the unreleased version that I'm using.

Try this:
B4X:
Private Sub DownloadAndTrackProgress (url As String, sFile As String) As ResumableSub
    Dim j As HttpJob
    j.Initialize("", Me)
    j.Download(url)
    #if debug
    'delete if using B4J v10.8+
    Sleep(0)
    #End If
    Dim TaskToJob As Map = HttpUtils2Service.TaskIdToJob
    Do While HttpUtils2Service.TaskIdToJob.IsInitialized = False
        Sleep(30)
    Loop
   
    Dim TaskId As Int
    For Each id As Int In TaskToJob.Keys
        If TaskToJob.Get(id) = j Then
            TaskId = id
            Exit
        End If
    Next
    Dim b() As Boolean = Array As Boolean(False)
    TrackProgress(j, b, TaskId)
    Wait For (j) JobDone (j As HttpJob)
    b(0) = True

    If j.Success Then
        Dim out As OutputStream = File.OpenOutput(File.DirTemp, sFile, False)
        File.Copy2(j.GetInputStream, out)
        out.Close '<------ very important
    End If

    j.Release
    Return j.Success
End Sub

@Erel !!!!

Now is Working in my project!!.. Changing existing sub for above sub ?

The line
B4X:
Sleep(0)
was the key

EDIT!!
In my project in release mode does not work. I have deleted the lines
B4X:
#if debug.... #End If

Now works fine
 
Last edited:
Upvote 0

johnaaronrose

Active Member
Licensed User
Longtime User
@Erel !!!!

Now is Working in my project!!.. Changing existing sub for above sub ?

The line
B4X:
Sleep(0)
was the key

EDIT!!
In my project in release mode does not work. I have deleted the lines
B4X:
#if debug.... #End If

Now works fine
I presume that TrackProgress is a Sub with coding done by the developer (rather than a Library Sub). If so, could someone post the coding that it could have?
 
Upvote 0

Dadaista

Active Member
Licensed User
Longtime User
B4X:
Sub DownloadAndSaveFile (Link As String, sFile As String)
    Dialog.Title = sNomAPP & " NUEVA VERSION"
    Dim rs As ResumableSub = Dialog.Show("Hay una Nueva Versión Disponoble. ¿Quieres Instalarla?", "", "", "")'SI "" NO
    Dialog.GetButton(xui.DialogResponse_Positive).TextColor = xui.Color_Green
    Dialog.GetButton(xui.DialogResponse_Cancel).TextColor = xui.Color_Red
    Wait For (rs) Complete (pp As Int)
    If pp = xui.DialogResponse_Positive Then
        ProgressBarTrackDownload.Progress = 0
        LblTrackDownload.Text = 0
        LblTrackDownloadTotal.Text = 0
        MostrarPanel2(PnlTrackDownload, PnlCaja)
        Wait For (DownloadAndTrackProgress(Link, sFile)) Complete (Success As Boolean)
        If Success Then
            Sleep(1000)
            PnlTrackDownload.Visible = False
            '***** BLUR
            BlurScreen(False, PnlCaja)
            '***** BLUR
            
                        
            '**********************************************************
            'EJECUTAR LA INSTALACION DESDE EL SHELL.
            'AÑADIR JSHELL EN LAS LIBRERIAS
'            Dim shell As Shell
'           
'            shell.Initialize("shell", File.DirTemp & "\" & sFile, Null)
'            shell.WorkingDirectory = File.DirTemp
'            shell.Run(-1)
            'EJECUTAR LA INSTALACION DESDE EL SHELL.
            '**********************************************************
            
            '**********************************************************
            'SALVA EL ARCHIVO DONDE QUIERA EL USUARIO PARA LUEGO INSTALARLO
'            Dim f As String
'            Dim path As String
'            Dim sNombre As String
'            Dim FileSaved As FileChooser
'            FileSaved.Initialize
'            FileSaved.Title = "Guardar Fichero de Actualización"
'            FileSaved.SetExtensionFilter("Guardar Actualizacion", Array As String("*.exe"))
'            FileSaved.InitialFileName = sFile
'            f = FileSaved.ShowSave(MainForm)
'            If f = "" Then Return
'            path = f.SubString2(0, f.LastIndexOf("\"))
'            sNombre = f.SubString(f.LastIndexOf("\") + 1)
'            File.Copy(File.DirTemp, sFile, path, sNombre)
            'SALVA EL ARCHIVO DONDE QUIERA EL USUARIO PARA LUEGO INSTALARLO
            '**********************************************************
            
            fx.ShowExternalDocument(File.GetUri(File.DirTemp, sFile))
            ExitApplication
        Else
            'ERROR
            Dialog.Title = sNomAPP
            Dialog.ButtonsTextColor = xui.Color_Red
            Dialog.Show("Ha Ocurrido un Error en la Descarga. Inténtelo Más Tarde", "", "", "")
        End If
    End If
End Sub

Private Sub DownloadAndTrackProgress (url As String, sFile As String) As ResumableSub
    '***************************************************************************************************
    'PARA USARLO HAY QUE AÑADIR "HU2_PUBLIC" A SIMBOLOS CONDICIONALES EN LA CONFIGURACION DEL COMPILADOR
    '***************************************************************************************************
    Dim j As HttpJob
    j.Initialize("", Me)
    j.Download(url)
    
    Sleep(0)    'SI QUITO ESTO NO FUNCIONA!!!!
    
    Dim TaskToJob As Map = HttpUtils2Service.TaskIdToJob
    Do While HttpUtils2Service.TaskIdToJob.IsInitialized = False
        Sleep(30)
    Loop
        
    Dim TaskId As Int
    For Each id As Int In TaskToJob.Keys
        If TaskToJob.Get(id) = j Then
            TaskId = id
            Exit
        End If
    Next
    Dim b() As Boolean = Array As Boolean(False)
    TrackProgress(j, b, TaskId)
    Wait For (j) JobDone (j As HttpJob)
    b(0) = True
    
    'SALVA EL FICHERO
    If j.Success Then
        LblTrackDownload.Text = LblTrackDownloadTotal.Text
        ProgressBarTrackDownload.Progress = 100
        Dim out As OutputStream = File.OpenOutput(File.DirTemp, sFile, False)
        File.Copy2(j.GetInputStream, out)
        out.Close '<------ very important
    End If
    'SALVA EL FICHERO
    
    j.Release
    Return j.Success
End Sub

Private Sub TrackProgress (j As HttpJob, Stop() As Boolean, TaskId As Int)
    Do While Stop(0) = False
        If j.Out.IsInitialized Then
            Dim TotalLength As Long = j.Response.ContentLength
            Dim size As Long = File.Size(HttpUtils2Service.TempFolder, TaskId)
            ProgressBarTrackDownload.Progress = 100 * size / TotalLength
            LblTrackDownload.Text = size
            LblTrackDownloadTotal.Text = TotalLength
            'Log(size & ", " & TotalLength)
        End If
        Sleep(100)
    Loop
End Sub

Sub MostrarPanel2 (PanelMostrar As B4XView, PanelOrigen As B4XView)
    Dim a As Int = 30
    PanelOrigen.Enabled = False
    PanelMostrar.Visible = True
    PanelMostrar.Top = (MainForm.RootPane.Top + (MainForm.RootPane.Height - PanelMostrar.Height) / 2) - a'ANTES 80
    PanelMostrar.Left = (MainForm.RootPane.Left + (MainForm.RootPane.Width - PanelMostrar.Width) / 2)
    BlurScreen(True, PanelOrigen)
End Sub

This is my code. It is working for me
Must delete code is not needed for you.
?


Image atached is a pane named "PnlTrackDownload"
 

Attachments

  • 2022-05-10.png
    2022-05-10.png
    7.7 KB · Views: 224
Upvote 0

johnaaronrose

Active Member
Licensed User
Longtime User
Thanks, Dadaista.
I have 2 questions about the code.
1. I don't understand the use of the Boolean array b to check whether the download has finished: Each element is defined with value False in DownloadAndTrackProgress. Then TrackProgress is called with array passed as a parameter. The parameter Stop(0), which has the value of b(0), is then used to loop continually in TrackProgress until its value becomes True. But it is not set to True in TrackProgress. But it is set to True after the 'Wait For' command (in Download AndTrackProgress) after the Job has Finished due the JobDone parameter in that command. I presume that this is because the TrackProgress sub will be continually invoked even after that command is executed. I guess that this is due to the way that Android code works in that code after a line of code is started even though that line of code has not finished execution. Am I correct?
2. Why use a Boolean array when only the first element is ever used rather than a Boolean variable?
 
Upvote 0
Top