A fairly common operation in Android apps is the need to download content to the device. While it is easy enough to construct a network call to download the required content, there is also a built in way which can be particularly useful if the content being downloaded should also be shared with other apps, or stored in a publicly accessible location on the device. In this short series of articles we’ll take a look at DownloadManager which can solve many of the common problems in a really easy to use API.
Previously we saw how to use DownloadManager to perform downloads of content without any of the fuss! However, there is much more that we can do and that’s what we’ll be looking at in this article.
If we take another look at what happens when we perform a download we can see that we get a notification while the download is in progress:
If we take a look at the notification itself we can see that it includes the name of the file being downloaded and an estimated remaining time:
We can actually control the notification. If we want to change when the notification is displayed we can do this by calling setNotificationVisibility()
(for API 11 and later, or the much simpler setShowRunningNotification()
from API 9)on the DownloadManager.Request object that we enqueue to DownloadManager. It is possible to actually suppress the notification altogether, but you’ll need to have the DOWNLOAD_WITHOUT_NOTIFICATION
permission in order to do so.
But it is also possible to control what appears in the notification using the setDescription()
and setTitle()
methods of DownloadManager.Request. setTitle()
allows is to change what appears in the file name field, and setDescription()
allows us to override what gets displayed in the remaining time field:
void download(Uri uri) { if (!isDownloading()) { register(); DownloadManager.Request request = new DownloadManager.Request(uri); request.setTitle("My hovercraft is full of eels"); request.setDescription("I am no longer infected"); downloadId = downloadManager.enqueue(request); } }
Personally I would prefer to avoid changing the description because the remaining time is actually quite useful for the user, but if we run that we can see how it alters the notification:
Often servers may require specific HTTP headers to be included, such as a session ID. These can easily be added using the addRequestHeader()
method on DownloadManager.Request.
If a download is particularly large we may need to consider what impact the download may have on the user’s data allowance. There are a number of methods on DownloadManager.Request which can restrict the download to newtorks which aren’t going to cost the user money. The default settings are unrestricted, so it is really important to self-impose some restrictions if downloads are likely to be large. Downloads when roaming can be restricted using setAllowedOverRoaming()
; Specific types of network can be filtered using setAllowedNetworkTypes()
(on API 16 andf later we can also use setAllowedOverMetered()
.
We also have control over whether the content is visible to the OS following download. Calling allowScanningByMediaScanner()
before we enqueue a request will allow the system media scanner visibility of the content. For example, if we were to specify this when downloading an image, then the media scanner would be given visibility of the image one it was downloaded and it would appear in the image gallery once it had been scanned.
Another way that we can control where the content is visible is the setVisibleInDownloadsUi()
method of DownloadManager.Request. This controls whether the content and its download status are visible within the system Download app.
Finally, we can also control where the content is actually downloaded to on the device. By default it will be downloaded to the system area whichb is private tyo your app (although it can be shared to other apps as we saw in the previous article).One down-side of this is that it can be deleted by the system if it needs to free up space in the system area. One way to avoid this potential automatic deletion is to call setDestinationInExternalFilesDir()
which will store the content in your app’s private storage area on external storage.which would not normally be visible to the media scanner. If you want the content to be visible to media scanner then use setDestinationInExternalPublicDir()
instead and this will save it to public external storage instead. However, storing the content in public storage (available to all apps on the system) affects the ability to share it with other apps. More in this in a future post!
We can control all of that on a per-download basis, but there are also some general restrictions we can apply to all downloads and we’ll look at those in the next article.
Although there are only minimal changes to our sample app code from the previous article, the source code for this article is available here.
© 2016, Mark Allison. All rights reserved.
Copyright © 2016 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.