Downloading File properly in Android

Aung Kyaw Myint
4 min readJun 18, 2019

In Android development, developers have to work a lot with Retrofit and Volley for network operations like sending GET/POST request, uploading image, logging requests, adding headers etc . While these libraries are really helpful with these operations, when it comes to downloading a huge file, one would suggest using DownloadManager for the sake of thread management and flexibility. That is what this article is about: how to implement DownloadManager.

“ The download manager is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file.”

The advantages of using download manager are:

  • It performs all the HTTP interaction on background thread by default. You dont need to create any thread.
  • It gracefully handles connectivity issues if the network changes or device reboots by automatically retrying download after failure due to any reason.
  • It provides features like pause/ resume download thereby improving user experience.
  • Has a in built mechanism to inform the user of download progress using notification.

Add permission

We need to add permission for Internet to be able to use downloadmanager. Let’s do it.

Create Layout

We will create a layout with a button center in it which will initiate downloading the file.

Create Activity class

Create MainActivity class where we will initialize button object and implement click listener for it.

  • Note that we have also created a global long variable which will be used to store download identifier id. More about this in next section

Create DownloadManager.Request

To start download process, we need to prepare DownloadManger.Request which contains all the information to request a new download. While the URI is the only required parameter, if we don’t provide the file destination for downloaded file, the default is a shared volume where the system might delete your file if it needs to reclaim space for system use. So, first create a file destination and prepare the request. Detailed information about how to create files properly and share between apps can be found here.

Following are some important APIs used to set information of the download

  • setNotificationVisibility(int)
    This API is to control whether a system notification is shown while this download is running or when it is completed.
    It can takes any of the following predefined values:
    #VISIBILITY_HIDDEN
    #VISIBILITY_VISIBLE
    #VISIBILITY_VISIBLE_NOTIFY_COMPLETED
    If set to VISIBILITY_HIDDEN, this requires the permission android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
  • setDescription(String), setTitle(String)
    These APIs are used to set the description and title of the download notification (if displayed).
  • setDestinationInExternalFilesDir(Context ,String,String) , setDestinationUri(Uri), setDestinationInExternalPublicDir(String,String)
    These APIs are used to set the destination file path of the downloaded file. You can start a download even without specifying the destination, in which case file is temporarily stored in shared storage. Also if you are storing the file in external storage you need to add STORAGE permissions in the Manifest.
  • addRequestHeader(String,String)
    This API is used to add a request header to the HTTP request used to download the file

Apart from these they are a lot of other APIs like setAllowedOverRoaming(), setRequiresCharging(), setAllowedOverMetered() etc which define the conditions for the download to start. We have not used all the APIs in this DownloadManager Example but you can read more about them here.

Initiate Download

Once the request is set up, we can initiate download.

  • enqueue(request) returns a unique long ID which acts as an identifier for the download. Note that calling enqueue() doesnt necessarily start the download immediately. It rather schedules the download request in a queue. Once the DownloadManager is free is starts the download.
  • Important thing to note is how we initialize global variable downloadID . enqueue() returns an ID for the download, unique across the system. Global variable downloadID is used to store this ID. It is used to reference this download in future.

Download Complete

Download Manager is a separate system service which downloads files requested by client. Here your app is the client and once you call enqueue() from your app it is now the responsibility of Download Manager to schedule that download and save the file at destination. Therefore it is important that the client is informed when the download is completed. There are two ways to do this:

1. Listening to broadcast intent

Download manger sends ACTION_DOWNLOAD_COMPLETE broadcast action when a download completes. And you can identify the download with unique long ID previously returned by enqueue().

Register broadcast receiver in onCreate() method and unregister it in onDestroy() method.

2. Using Query method

While listening to broadcast intent is relatively easy, it is just sent when a download completes. What if we want to know if there is an error in downloading, keep track of download progress? No worries, you can get it done by using query method.

In the part where we can show download progress (inside DownloadManager.STATUS_RUNNING), there won’t be any return value for some time when we query DownloadManager. COLUMN_TOTAL_SIZE_BYTES. This will be a problem if you are downloading a small file like an image. The progress will be stuck at zero until we get the query value. In that kind of case, I’d suggest using loading dialog rather progress dialog. Another thing is don’t forget to use 100L rather than double when calculating progress. This is for getting more digits. If you use double, you might see numbers jumping steeply.

DownloadManger Example: Complete Code

Hope you enjoy the article and if you have better ways let me know in the comments. If you enjoy the article, don’t forget to clap. 👏

External Links:

--

--