Android Tutorial Downloading files using Service module

Status
Not open for further replies.
It is recommended to use HttpUtils2 instead of this code module. HttpUtils2 is more powerful and is easier to work with.

As discussed in the Services tutorial, some tasks are easier to implement with services than with activities.
In this example we will download an image file with a service and use it for the activity background.
This service can be used to download larger files as well.

The advantage of a service over activity in this case is that the service isn't paused when the application is in the background.

The steps required for downloading a file with this service is to first set the URL and the target file (the downloaded file is written to this file) and then call StartService.
The process global variables are used for passing those values to the service.
Process global variables can be accessed from all modules and are always available (even when the component is paused).

The service then downloads the file. When download completes the service uses CallSub to notify the Activity that the download has completed.
It is possible that the activity is not active when download is complete. In this case CallSub will not do anything. Press on Home button after starting the download to pause the activity.
We are handling this case in the activity resume event. When the activity resumes we check if we were in the middle of a download task. If yes, then we check the service JobStatus global variable which tells us whether the task has finished.

In most cases it is better to let the activity pull data from the service than pushing the data to the activity from the service. This way when the activity is ready it can grab the data and work with it.

If we were to download a large file in the background it is possible that the OS will at some point kill our process to free some memory. This will of course break our download.
To avoid this issue the service calls Service.StartForeground while downloading. This call marks our process as a foreground process. Which means that it is important not to kill it. A status bar notification is also displayed when the service is in this state.
You should be careful not to overuse this method and only call it if it is really problematic for your service to be killed.

When download completes we also check if the activity is currently active. If not we show a status bar notification that notifies the user that download has completed. When the user presses on the notification (by first dragging the status bar downwards) our activity is resumed.

The program is attached.
Main activity:
B4X:
'Activity module
Sub Process_Globals
    Dim image As Bitmap
End Sub

Sub Globals
    Dim btnDownload As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    'check if we already loaded the image previously.
    If image.IsInitialized Then
        Activity.SetBackgroundImage(image)
    End If
End Sub

Sub Activity_Resume
    'check if download has finished while the activity was paused
    If btnDownload.Enabled = False AND DownloadService.JobStatus = DownloadService.STATUS_DONE Then
        FinishDownload
    End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub btnDownload_Click
    Activity.Color = Colors.Black
    DownloadService.URL = "http://www.b4x.com/basic4android/images/designer1.png"
    DownloadService.Target = File.OpenOutput(File.DirInternalCache, "image.png", False)
    StartService(DownloadService)
    btnDownload.Enabled = False
End Sub

Sub FinishDownload
    'Load the saved image
    If DownloadService.DoneSuccessfully = True Then
        image = LoadBitmapSample(File.DirInternalCache, "image.png", _
         100%x, 100%y)
        Activity.SetBackgroundImage(image)
    End If
    btnDownload.Enabled = True
    DownloadService.JobStatus = DownloadService.STATUS_NONE
End Sub
DownloadService service:
B4X:
'Service module
Sub Process_Globals
    Dim HC As HttpClient
    'Activity is expected to set URL
    Dim URL As String
    Dim Target As OutputStream
    Dim JobStatus As Int
    Dim STATUS_NONE, STATUS_WORKING, STATUS_DONE As Int
    STATUS_NONE = 0
    STATUS_WORKING = 1
    STATUS_DONE = 2
    Dim DoneSuccessfully As Boolean
    Dim Notification1 As Notification
End Sub
Sub Service_Create
    HC.Initialize("HC")
    Notification1.Initialize
    Notification1.Icon = "icon" 'use the application icon file for the notification
    Notification1.Vibrate = False
End Sub

Sub Service_Start
    'URL and Target should be set by the calling module
    Dim request As HttpRequest
    request.InitializeGet(URL)
    HC.Execute(request, 1)
    JobStatus = STATUS_WORKING
    Notification1.SetInfo("Download Service example", "Downloading: " & URL, Main)
    Notification1.Sound = False
    'Make sure that the process is not killed during the download
    'This is important if the download is expected to be long.
    'This will also show the status bar notification
    Service.StartForeground(1, Notification1) 
End Sub

Sub HC_ResponseError (Reason As String, StatusCode As Int, TaskId As Int)
    ToastMessageShow("Error downloading file: " & Reason, True)
    DoneSuccessfully = False
    Finish
End Sub

Sub HC_ResponseSuccess (Response As HttpResponse, TaskId As Int)
    'Asynchronously download the stream
    Response.GetAsynchronously("Response", Target, True, TaskId)
End Sub

Sub Response_StreamFinish (Success As Boolean, TaskId As Int)
    If Success = False Then
        ToastMessageShow("Error downloading file: " & LastException.Message, True)
    Else
        ToastMessageShow("Download successfully.", True)
    End If
    DoneSuccessfully = Success
    Finish
End Sub

Sub Finish
    Log("Service finished downloading")
    JobStatus = STATUS_DONE
    'Notify the activity that the download has finished.
    'It will do nothing if the activity is currently paused.
    CallSub(Main, "FinishDownload")
    Service.StopForeground(1) 'Return the service to the "background" (also removes the ongoing notification)
    If IsPaused(Main) Then
        'The activity is paused. The user is probably busy with some other activity.
        'Notify the user that the download has finished
        Notification1.Sound = True
        Notification1.SetInfo("Download Service", "Download complete", Main)
        Notification1.AutoCancel = True
        Notification1.Notify(1)
    End If
End Sub
Sub Service_Destroy

End Sub
 

Attachments

  • DownloadService.zip
    6.9 KB · Views: 6,604

philgoodgood

Member
Licensed User
Longtime User
hello,

very good english Erel, "Google translator" was too happy .... and so do i :sign0060:
 

Malky

Active Member
Licensed User
Longtime User
I am trying to get a simple listview up, but have problems obtaining the image?

I need to acquire the image, but keep getting an error.

It is an essential function of my app and I'm pulling my hair out going in circles.

The httputils2 example seems the best, but like all of them, they just display the image in a background image.

I hope to store the image files onto the SD card, but returning the image seems to be the problem?

I've attached the bas file if it helps?

Malky
 

little3399

Active Member
Licensed User
Longtime User
in downloadservice example Notification1.Icon="Icon" the icon file can be change in other file name ? such as myicon ? TKS!
 

DonManfred

Expert
Licensed User
Longtime User
Status
Not open for further replies.
Top