Android Question incomplete download of large files

Dieter Baumgartner

Member
Licensed User
Longtime User
I have running a APP which downloads large mp3- files from a Server. It runs fine on most mobiles, but i get more often a error report, that it only downloads 20 sec. or 202 kb mostly on Samsung S3 or Samsung S4.
I have a progress bar and it seems that it runs 100 % but then it only downloaded 20 sec. of files that are more than 30 min.
I use the newest service modules "DownloadService", "Httputils2Service","Httpjob" with the HTTP version 1.31 lib. On my Android 2.3 devices i have no problem at all.

Does anyone have a idea, why it only downloads that mini- part of the files on some of the HITECH- mobiles ? Is there a Android 4.x problem ?

B4X:
Sub downloadMeditation (CursorRes As Cursor)
Dim dd As DownloadData

If CheckConnection = False Then
Msgbox("Bitte Internetverbindung herstellen, damit Datei heruntergeladen werden kann","Aktuell keine Internetverbindung ")
Return
End If

If isdownload = False Then 'Ein Download läuft bereits, keinen 2. starten
pbdl.BringToFront
pbdl.Visible = True
btncancel.BringToFront
btncancel.Visible = True
downloadFileName = CursorRes.GetString("Dateiname")
dd.url = "http://www.yoga-urlaub.com/meditationen/"&downloadFileName
ToastMessageShow("Bitte um Geduld, bis "&CursorRes.GetString("Titel")& " geladen ist.",True)
dd.EventName = "dd"
dd.Target = Me
CallSubDelayed2(DownloadService, "StartDownload", dd)
isdownload = True 'Merker, dass gerade ein Download läuft
Else
pbdl.BringToFront
pbdl.Visible = True
btncancel.BringToFront
btncancel.Visible = True
'Msgbox("Bitte warten, bis der aktuelle Download abgeschlossen ist!","Download aktiv")
End If
End Sub


Sub dd_Progress(Progress As Long, Total As Long)
pbdl.Progress = Progress / Total * 100
'Label1.Text = NumberFormat(Progress / 1024, 0, 0) & "KB / " & _
' NumberFormat(Total / 1024, 0, 0) & "KB"
End Sub

Sub dd_Complete(job As HttpJob)
Log("Job completed: " & job.Success)
isdownload = False
'egal ob Erfolg oder nicht, Dateiname wieder zurücksetzen
downloadFileName = ""
 
End Sub

DownloadService:
Private Sub StartTimer (Target As Object)
Dim n As Notification
n.Initialize
n.Icon = "icon"
n.Vibrate = False
n.Sound = False
n.Light = False
datVerz = Main.sounddir 'Verzeichnis, wo die Meditationen gespeichert werden
datName = zeigeTitel.downloadFileName
Log("Verzeichnis: "& datVerz & ", Datei: "&datName)
n.SetInfo("Lade gerade "& datName & " ...", "", Main)
Service.StartForeground(1, n)
timer1.Enabled = True
pw.PartialLock
pw.KeepAlive(False)
End Sub

Private Sub EndTimer
Service.StopForeground(1)
timer1.Enabled = False
pw.ReleasePartialLock
pw.ReleaseKeepAlive
End Sub

Public Sub StartDownload(data As DownloadData)
If jobs.ContainsKey(data.url) Then
Log("Ignoring duplicate request.")
Return
End If
Dim J As HttpJob
J.Initialize(data.url, Me)
Dim tag As JobTag
tag.Initialize
tag.data = data
J.tag = tag
jobs.Put(data.url, J)
J.Download(data.url)
If timer1.Enabled = False Then StartTimer(data.Target)
End Sub

Public Sub CancelDownload(url As String)
If jobs.ContainsKey(url) = False Then
Log("Ignoring cancel request.")
Return
End If
Dim job As HttpJob = jobs.Get(url)
Dim jt As JobTag = job.Tag
If jt.CountingStream.IsInitialized Then
jt.CountingStream.Close
Else
jt.Data.url = ""
End If
End Sub

Sub timer1_tick
For Each job As HttpJob In jobs.Values
Dim jt As JobTag = job.Tag
If jt.CountingStream.IsInitialized Then
CallSub3(jt.Data.Target, jt.Data.EventName & "_Progress", _
jt.CountingStream.Count, jt.Total)
End If
Next
End Sub

HttpUtilsService:
'Modified version of HttpUtils2
'Service module
Sub Process_Globals
Private hc As HttpClient
Private TaskIdToJob As Map
Public TempFolder As String
Private taskCounter As Int
End Sub

Sub Service_Create
'TempFolder = File.DirInternalCache
TempFolder = Main.sounddir
hc.Initialize("hc")
TaskIdToJob.Initialize
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Sub Service_Destroy

End Sub

Public Sub SubmitJob(job As HttpJob) As Int
taskCounter = taskCounter + 1
TaskIdToJob.Put(taskCounter, job)
If job.Username <> "" AND job.Password <> "" Then
hc.ExecuteCredentials(job.GetRequest, taskCounter, job.Username, job.Password)
Else
hc.Execute(job.GetRequest, taskCounter)
End If
Return taskCounter
End Sub

Sub hc_ResponseSuccess (Response As HttpResponse, TaskId As Int)
' ' ********** Modified code *************
' Dim cs As CountingOutputStream
' cs.Initialize(File.OpenOutput(TempFolder, TaskId, False))
' Dim j As HttpJob = TaskIdToJob.Get(TaskId)
' If j.Tag Is JobTag Then
' Dim jt As JobTag = j.Tag
' jt.CountingStream = cs
' jt.Total = Response.ContentLength
' If jt.Data.url = "" Then
' Log("Job cancelled before downloaded started")
' cs.Close
' End If
' End If
' Response.GetAsynchronously("response", cs , _
' True, TaskId)
' '**************************************
Response.GetAsynchronously("response", File.OpenOutput(TempFolder, TaskId, False), _
True, TaskId)
End Sub

Sub Response_StreamFinish (Success As Boolean, TaskId As Int)
If Success Then
CompleteJob(TaskId, Success, "")
Else
CompleteJob(TaskId, Success, LastException.Message)
End If
End Sub

Sub hc_ResponseError (Response As HttpResponse, Reason As String, StatusCode As Int, TaskId As Int)
If Response <> Null Then
Try
Log(Response.GetString("UTF8"))
Catch
Log("Failed to read error message.")
End Try
Response.Release
End If
CompleteJob(TaskId, False, Reason)
End Sub

Sub CompleteJob(TaskId As Int, success As Boolean, errorMessage As String)
Dim job As HttpJob
job = TaskIdToJob.Get(TaskId)
TaskIdToJob.Remove(TaskId)
job.success = success
job.errorMessage = errorMessage
job.Complete(TaskId)
End Sub

'HttpUtils2 version 2.00
'Class module
Sub Class_Globals
Public JobName As String
Public Success As Boolean
Public Username, Password As String
Public ErrorMessage As String
Private target As Object
Private mLink As String
Public taskId As String
Private req As HttpRequest
Public Tag As Object
Public Dateiname As String
Private n As AdvancedNotification
End Sub

'Initializes the Job.
'Name - The job's name. Note that the name doesn't need to be unique.
'TargetModule - The activity or service that will handle the JobDone event.
Public Sub Initialize (Name As String, TargetModule As Object)
JobName = Name
target = TargetModule

End Sub
'Sends a POST request with the given data as the post data.
Public Sub PostString(Link As String, Text As String)
PostBytes(Link, Text.GetBytes("UTF8"))
End Sub

'Sends a POST request with the given string as the post data
Public Sub PostBytes(Link As String, Data() As Byte)
mLink = Link
req.InitializePost2(Link, Data)
CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)
End Sub

'Sends a POST request with the given file as the post data.
'This method doesn't work with assets files.
Public Sub PostFile(Link As String, Dir As String, FileName As String)
Dim length As Int
If Dir = File.DirAssets Then
Log("Cannot send files from the assets folder.")
Return
End If
length = File.Size(Dir, FileName)
Dim In As InputStream
In = File.OpenInput(Dir, FileName)
' If length < 1000000 Then '1mb
' 'There are advantages for sending the file as bytes array. It allows the Http library to resend the data
' 'if it failed in the first time.
' Dim out As OutputStream
' out.InitializeToBytesArray(length)
' File.Copy2(In, out)
' PostBytes(Link, out.ToBytesArray)
' Else
req.InitializePost(Link, In, length)
CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)
' End If
End Sub
'Submits a HTTP GET request.
'Consider using Download2 if the parameters should be escaped.
Public Sub Download(Link As String)
mLink = Link
req.InitializeGet(Link)
CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)
End Sub
'Submits a HTTP GET request.
'Encodes illegal parameter characters.
'<code>Example:
'job.Download2("http://www.example.com", _
' Array As String("key1", "value1", "key2", "value2"))</code>
Public Sub Download2(Link As String, Parameters() As String)
mLink = Link
Dim sb As StringBuilder
sb.Initialize
sb.Append(Link)
If Parameters.Length > 0 Then sb.Append("?")
Dim su As StringUtils
For i = 0 To Parameters.Length - 1 Step 2
If i > 0 Then sb.Append("&")
sb.Append(su.EncodeUrl(Parameters(i), "UTF8")).Append("=")
sb.Append(su.EncodeUrl(Parameters(i + 1), "UTF8"))
Next
req.InitializeGet(sb.ToString)
CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)
End Sub

'Called by the service to get the request
Public Sub GetRequest As HttpRequest
Return req
End Sub

'Called by the service when job completes
Public Sub Complete (id As Int)
taskId = id
CallSubDelayed2(target, "JobDone", Me)
End Sub

'Should be called to free resources held by this job.
Public Sub Release

End Sub
'Returns the response as a string encoded with UTF8.
Public Sub GetString As String
Return GetString2("UTF8")
End Sub

'Returns the response as a string.
Public Sub GetString2(Encoding As String) As String
Dim tr As TextReader
tr.Initialize2(File.OpenInput(HttpUtils2Service.TempFolder, taskId), Encoding)
Dim res As String
res = tr.ReadAll
tr.Close
Return res
End Sub

'Returns the response as a bitmap
Public Sub GetBitmap As Bitmap
Dim b As Bitmap
b = LoadBitmap(HttpUtils2Service.TempFolder, taskId)
Return b
End Sub

Sub GetInputStream As InputStream
Dim In As InputStream
In = File.OpenInput(HttpUtils2Service.TempFolder, taskId)
Return In
End Sub
 
Last edited:

warwound

Expert
Licensed User
Longtime User
Do you need to support versions of Android older than Gingerbread?
If not then an alternative might be to look at the DownloadManager library.

In fact if you have time you might want to try it on the HITECH devices anyway and see if the problem persists.

Martin.
 
Upvote 0

Dieter Baumgartner

Member
Licensed User
Longtime User
Erel, the code is the same as in your example.
There is no error visible at all. but some users tell me, that the mp3- files they load are only 20 sec. long. As far as i know, it where only Samsung S3 and S4 and it was on one HTC, all newer mobiles. On the older mobiles i have everything always downloads completely.
I tried with changing http-Parameters, but no change !
Where could it be, that the code thinks that it successfully finishes the download after about 202 kb which maybe 20 sec. mp3-file on these systems.
B4X:
Sub Service_Create
  Dim ver As String
   
    ver = "HTTP_1_1"
    'TempFolder = File.DirInternalCache
    TempFolder = Main.sounddir
    hc.Initialize("hc")
    'hc.SetHttpParameter("PROTOCOL_VERSION",ver)  'HTTP_1_1 ist Standard
    hc.sethttpparameter("CONN_KEEP_ALIVE",300000)
    hc.sethttpparameter("STALE_CONNECTION_CHECK",False)
    TaskIdToJob.Initialize
End Sub
Would it be better to use Downloadmanager Library for downloading large files instead of the combination of "DownloadService", "Httptils2Service" and "HTTPJob" ?

Is there somewhere a example of how to work with this lib ?
 
Upvote 0

Dieter Baumgartner

Member
Licensed User
Longtime User
thank you martin, i found the example. I thought i tried once the downloadmanager- LIB, but will try again now. Thought, the new method might work better, because it was newer. I will post here, if the user has no problem with the APP when i use the Library.
 
Upvote 0

Dieter Baumgartner

Member
Licensed User
Longtime User
So, i changed to use the downloadmanager- LIB instead of the code similar to EREL's "Download huge files with HttpUtils2". It seems now to run better, thank you Martin and Erel. Erels example code seems to make problems on some HITECH- mobiles like Galaxy S3 or S4 and some HTC devices. The user told me, that it downloads only 20 sec. of a mp3- file or about 202 kb. I don't know where there could be the problem, but with DownloaderService the same APP worked on one of theses devices. Perhaps it is also a Android 4.X issue, on 2.X devices no problem with the HTTPUtils2- example.
 
Upvote 0
Top